#!/bin/bash

set -u

cd "$(dirname "$0")"/.. || exit 1

difs () {
    local ref=$1
    local namefilter=$2
    local -i errs=0
    for f in tests/*.input.txt; do
        name="$(basename "${f%.input.txt}")"
        [[ ${name} = *${namefilter}* ]] || continue
        out=$(dif1 "${ref}" "${name}")
        # Count number of lines starting with '-' except the initial header lines:
        errs+=$(tail -n+3 <<<"${out}" | grep -c '^-')
        [[ -n "${out}" ]] && wdif "${ref}" <<<"$out"
    done
    # TODO: count *lines* of fails, not just files failed!
    # If number of errors <= THRESHOLD, we don't fail
    if [[ "${errs}" -le "${THRESHOLD:-0}" ]]; then
        return 0
    else
        return "${errs}"
    fi
}
wdif () {
    local ref=$1
    local colorspec
    case ${ref} in
        expected) colorspec=green,bcyan ;;
        gold) colorspec=brown,bcyan ;;
        *) echo "ERROR bug in call to wdif" >&2; exit 1 ;;
    esac
    if command -V dwdiff &>/dev/null; then
        if [[ -t 1 ]]; then     # stdout is a terminal, use colours
            dwdiff --diff-input --color="${colorspec}"
        else
            dwdiff --diff-input
        fi
    else
        cat
    fi
}
dif1 () {
    local ref=$1
    local name=$2
    case ${ref} in
        expected) reffile=tests/expected/"${name}".expected.txt ;;
        gold) reffile=tests/gold/"${name}".gold.txt ;;
        *) echo "ERROR bug in call to dif1" >&2; exit 1 ;;
    esac
    (
        set -o pipefail
        diff -U0 -I'^nno-nob\|AP_SRC'                     \
             "${reffile}"                                 \
             tests/current/"${name}".current.txt          \
            | awk '/./&&!p { print "@@"; p++ } { print }'
              # Prepending @@ to non-empty diff ensures file paths are coloured too
    )
}

assert-translated () {
    for f in tests/*.input.txt; do
        name="$(basename "${f%.input.txt}")"
        [[ ${name} = *${namefilter}* ]] || continue
        cur=tests/current/"${name}".current.txt
        if [[ ! -f "${cur}" ]]; then
            echo "${cur} not found" >&2
            echo >&2
            echo "Please run '$0 translate' first" >&2
            exit 1
        fi
    done
}

assert-usage () {
    echo "USAGE:

$0 translate      # run this after your edits and compiles
$0 diff-expected  # compare result of 'translate' with expected output
$0 diff-gold      # compare result of 'translate' with gold set
$0 update         # update the current expected output with result of 'translate'
$0 expect         # add sentence from stdin as new test with current as expected
"
    exit 1
}

get-mode () {
    case $1 in
        *nno-nob)   echo nno-nob;;
        *nob-nno_e) echo nob-nno_e;;
        *)          echo nob-nno ;; # e.g. cappelen, motvariant
    esac
}

setvars () {
    if [[ $1 = *nob-nno_cappelen ]]; then
        # shellcheck source=./cappelen
        source t/cappelen
    elif [[ $1 = *nob-nno_motvariant ]]; then
        # shellcheck source=./motvariant
        source t/motvariant
    else
        export AP_SETVAR=''
    fi
}

filter_stderr () {
    # Drop some warnings we don't care about
    grep -v                                                                           \
         -e '^Warning: matching case-sensitively since processor state size >= 65536' \
         -e '^Warning: compoundAnalysis.s MAX_COMBINATIONS exceeded for'              \
         -e '^         gave up at char [0-9]' >&2
}

[[ $# -lt 1 || $# -gt 2 ]] && assert-usage

namefilter=''
[[ $# -ge 2 ]] && namefilter=$2

case $1 in
    translate)
        mkdir -p tests/current
        for f in tests/*.input.txt; do
            name="$(basename "${f%.input.txt}")"
            [[ ${name} = *${namefilter}* ]] || continue
            # shellcheck disable=SC2311
            mode=$(get-mode "${name}")
            setvars "${name}"
            apertium -d . "${mode}"                            \
                     < tests/"${name}".input.txt               \
                     > tests/current/"${name}".current.txt     \
                     2>>>(filter_stderr || true)
        done
        ;;
    update)
        assert-translated "${namefilter}"
        for cur in tests/current/*.current.txt; do
            name="$(basename "${cur%.current.txt}")"
            cp -v "${cur}" tests/expected/"${name}".expected.txt
        done
        ;;
    diff-expected)
        assert-translated "${namefilter}"
        difs expected "${namefilter}"
        ;;
    diff-gold)
        assert-translated "${namefilter}"
        difs gold "${namefilter}"
        ;;
    expect)
        if [[ -z "${namefilter}" ]]; then echo "Needs a test set, e.g. 'ymse'"; exit 1; fi
        seen=false
        for f in tests/*.input.txt; do
            name="$(basename "${f%.input.txt}")"
            [[ ${name} = *${namefilter}* ]] || continue
            # shellcheck disable=SC2311
            mode=$(get-mode "${name}")
            setvars "${name}"
            expf=tests/expected/"${name}".expected.txt
            goldf=tests/gold/"${name}".gold.txt
            input=$(cat)
            [[ "${input}" = *[.?\!] ]] || input="${input}." # ensure final punctuation
            echo "${input}" | tee -a "${f}" | apertium -d . "${mode}" | tee -a "${expf}" "${goldf}"
            seen=true
            break
        done
        if ! ${seen}; then echo "Unknown test set '${namefilter}'"; echo "(couldn't find file matching tests/*${namefilter}*.input.txt – try 'ymse' if unsure)"; exit 1; fi
        ;;
    *)
        assert-usage
        ;;
esac
