#!/bin/bash

set -eu
set -o pipefail

## Helper Functions

function loud {
  echo "$ $@"
  $@
}

function stack {
  $HOME/.local/bin/stack --no-terminal "$@"
}

# Source: https://github.com/travis-ci/travis-build/blob/fc4ae8a2ffa1f2b3a2f62533bbc4f8a9be19a8ae/lib/travis/build/script/templates/header.sh#L104-L123
RED="\033[31;1m"
GREEN="\033[32;1m"
RESET="\033[0m"
function travis_retry {
  local result=0
  local count=1
  while [ $count -le 3 ]; do
    [ $result -ne 0 ] && {
      echo -e "\n${RED}The command \"$@\" failed. Retrying, $count of 3.${RESET}\n" >&2
    }
    set +e
    "$@"
    result=$?
    set -e
    [ $result -eq 0 ] && break
    count=$(($count + 1))
    sleep 1
  done

  [ $count -eq 4 ] && {
    echo "\n${RED}The command \"$@\" failed 3 times.${RESET}\n" >&2
  }

  return $result
}

function prevent_timeout {
  local cmd="$@"

  $cmd &
  local cmd_pid=$!

  poke_stdout &
  local poke_pid=$!

  wait $cmd_pid
  exit_code=$?

  kill $poke_pid
  (wait $poke_pid 2>/dev/null) || true

  return $exit_code
}

function poke_stdout {
  # Print an invisible character every minute
  while true; do
    echo -ne "\xE2\x80\x8B"
    sleep 60
  done
}

function pastebin {
  curl -s -F 'clbin=<-' https://clbin.com
}

## Setup Stages

function install_smt {
  local smt="$1"

  mkdir -p "${HOME}/.local/bin"
  loud curl "http://goto.ucsd.edu/~gridaphobe/$smt" -o "${HOME}/.local/bin/$smt"
  loud chmod a+x "${HOME}/.local/bin/$smt"
}

function install_stack {
  local stack_version="$1"

  mkdir -p "${HOME}/.local/bin"
  mkdir -p '/tmp/stack'

  pushd '/tmp/stack'

  local dir_name="stack-${stack_version}-x86_64-linux"
  local archive_name="${dir_name}.tar.gz"
  local stack_url="https://github.com/commercialhaskell/stack/releases/download/v${stack_version}/${archive_name}"

  loud wget "${stack_url}"
  loud tar -xzvf "./${archive_name}"
  loud cp "./${dir_name}/stack" "${HOME}/.local/bin/stack"
  loud chmod a+x "${HOME}/.local/bin/stack"

  popd
}

function configure_stack {
  local ghc_version="$1"

  echo "Configuring stack.yaml for ${ghc_version}..."

  cat << EOF > 'stack.yaml'
resolver: ${ghc_version}

packages:
- ./liquid-fixpoint
- .
EOF

  loud cat stack.yaml
}

function setup_ghc {
  loud stack setup
  loud stack ghc -- --version
}

function install_dependencies {
  echo "Solving dependency constraints..."
  loud stack update
  loud stack solver --update-config

  echo "Installing dependencies..."
  loud stack build liquidhaskell --only-dependencies --test --no-run-tests --no-haddock-deps
}

## Building & Testing Stages

function do_build {
  loud stack build liquidhaskell --test --no-run-tests --haddock --no-haddock-deps --flag liquidhaskell:devel
}

function do_test {
  local tests="$1"
  local smt="$2"

  local test_runner="$(stack path --dist-dir)/build/test/test"

  loud prevent_timeout stack exec -- "${test_runner}" --pattern "$tests/" --smtsolver "$smt" -j2 +RTS -N2 -RTS
}

function dump_fail_logs {
  find tests/logs/cur -type f -name '*log.fail' -print0 | while IFS= read -r -d $'\0' file; do
    echo "${file}:"
    echo "    $(pastebin < "${file}")"
  done
}

## Run Test Stage

stage="$1"
shift

$stage "$@"