#!/usr/bin/env bash
set -euo pipefail

build_root=$1
mode=$2
entry_src=$3
lib_src=$4

cli_dir="$build_root/src/cli"
php2ast="$cli_dir/phpefc-php2ast"
phpast2phpir="$cli_dir/phpefc-phpast2phpir"
phpir2valair="$cli_dir/phpefc-phpir2valair"
valair2vala="$cli_dir/phpefc-valair2vala"
valair_optimize="$cli_dir/phpefc-valair-optimize-typing"

for tool in "$php2ast" "$phpast2phpir" "$phpir2valair" "$valair_optimize" "$valair2vala"; do
    if [ ! -x "$tool" ]; then
        echo "missing built tool: $tool" >&2
        exit 99
    fi
done

source_prefix() {
    python3 - "$1" <<'PY'
import re, sys
path = sys.argv[1].replace('\\', '/')
path = path.rsplit('/', 1)[-1]
part = re.sub(r'[^A-Za-z0-9_]+', '_', path).strip('_') or 'unknown_php'
if not re.match(r'^[A-Za-z_]', part):
    part = '_' + part
print(part)
PY
}

line_of() {
    local needle=$1 file=$2
    awk -v needle="$needle" 'index($0, needle) { print NR; exit }' "$file"
}

work=${MESON_TEST_TMPDIR:-}
if [ -z "$work" ]; then
    work=$(mktemp -d)
    trap 'rm -rf "$work"' EXIT
fi
mkdir -p "$work"

lib_real=$(realpath "$lib_src")
lib_prefix=$(source_prefix "$lib_real")
lib_register="phpef_file_${lib_prefix}__register_functions"
lib_call='PhpefRuntimeCore.call_function("funcfromlib",'

entry_ast="$work/entry.phpast"
lib_ast="$work/lib.phpast"
entry_phpir="$work/entry.phpir"
lib_phpir="$work/lib.phpir"
entry_valair="$work/entry.valair"
lib_valair="$work/lib.valair"
entry_vala="$work/entry.vala"
lib_vala="$work/lib.vala"

"$php2ast" "$entry_src" "$entry_ast" >/dev/null
"$php2ast" "$lib_src" "$lib_ast" >/dev/null
"$phpast2phpir" "$entry_ast" "$entry_phpir" --external-phpast "$lib_ast" >/dev/null
"$phpast2phpir" "$lib_ast" "$lib_phpir" --external-phpast "$entry_ast" >/dev/null
"$phpir2valair" "$entry_phpir" "$entry_valair" --external-phpir "$lib_phpir" >/dev/null
"$phpir2valair" "$lib_phpir" "$lib_valair" --external-phpir "$entry_phpir" >/dev/null
"$valair_optimize" "$entry_valair" "$entry_valair.afteropt.typing-zval2static" >/dev/null
"$valair_optimize" "$lib_valair" "$lib_valair.afteropt.typing-zval2static" >/dev/null
"$valair2vala" "$entry_valair.afteropt.typing-zval2static" "$entry_vala" >/dev/null
"$valair2vala" "$lib_valair.afteropt.typing-zval2static" "$lib_vala" --no-main >/dev/null

case "$mode" in
    before-include-reject)
        call_line=$(line_of "${lib_call}" "$entry_vala")
        reg_line=$(line_of "${lib_register}();" "$entry_vala")
        if [ -z "$call_line" ] || [ -z "$reg_line" ] || [ "$call_line" -ge "$reg_line" ]; then
            echo "expected call-before-include to lower to runtime registry call before include registration" >&2
            cat "$entry_vala" >&2
            exit 1
        fi
        if grep -Fq '__registered' "$entry_vala" || grep -Fq '__call(' "$entry_vala"; then
            echo "old bool/__call registration model leaked into generated Vala" >&2
            cat "$entry_vala" >&2
            exit 1
        fi
        printf "ok 1 - source-set function call before include lowers to runtime registry call before registration\n"
        ;;
    after-include-accept)
        reg_line=$(line_of "${lib_register}();" "$entry_vala")
        call_line=$(line_of "${lib_call}" "$entry_vala")
        if [ -z "$call_line" ] || [ -z "$reg_line" ] || [ "$reg_line" -ge "$call_line" ]; then
            echo "expected include to register functions before registry call" >&2
            cat "$entry_vala" >&2
            exit 1
        fi
        if ! grep -Fq 'PhpefRuntimeCore.register_function("funcfromlib"' "$lib_vala"; then
            echo "included source must register PHP-visible function name in runtime registry" >&2
            cat "$lib_vala" >&2
            exit 1
        fi
        if grep -Fq '__registered' "$entry_vala" || grep -Fq '__call(' "$entry_vala" || grep -Fq '__registered' "$lib_vala" || grep -Fq '__call(' "$lib_vala"; then
            echo "old bool/__call registration model leaked into generated Vala" >&2
            cat "$entry_vala" "$lib_vala" >&2
            exit 1
        fi
        printf "ok 1 - source-set function call after include is registered before registry call\n"
        ;;
    *)
        echo "unknown mode: $mode" >&2
        exit 2
        ;;
esac
