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

build_root=$1
src=$2

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"
c_add_source_lines="$cli_dir/phpefc-c-add-source-lines"

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

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

phpast="$work/function_source_lines.phpast"
phpir="$work/function_source_lines.phpir"
valair="$work/function_source_lines.valair"
vala="$work/function_source_lines.vala"
fake_c="$work/function_source_lines.c"
mapped_c="$work/function_source_lines.mapped.c"
debug_bundle="$work/function_source_lines.debug.json"

"$php2ast" "$src" "$phpast"
"$phpast2phpir" "$phpast" "$phpir"
"$phpir2valair" "$phpir" "$valair"
"$valair_optimize" "$valair" "$valair.afteropt.typing-zval2static"
"$valair2vala" "$valair.afteropt.typing-zval2static" "$vala"
if grep -F 'PhpefRuntimeCore.register_function(' "$vala" | grep -Fq "$src"; then
    printf 'register_function must not contain PHP source path: %s\n' "$src" >&2
    cat "$vala" >&2
    exit 1
fi
if ! grep -Eq 'PhpefRuntimeCore\.register_function\(\"[^\"]+\", [^,]+, \"[^\"]+\", [0-9]+, [0-9]+\);' "$vala"; then
    printf 'expected register_function(name, handler, handler_symbol, min_args, max_args) in generated Vala\n' >&2
    cat "$vala" >&2
    exit 1
fi


map_info=$(python3 - "$src" "$vala" <<'PY'
import json
import re
import sys
from pathlib import Path

src, vala = sys.argv[1:]
text = Path(vala).read_text()
match = re.search(r'PHPEFC-C-SOURCE-LINES-BEGIN\n(.*?)\nPHPEFC-C-SOURCE-LINES-END', text, re.S)
if not match:
    raise SystemExit('source-map comment missing from generated Vala')
source_map = json.loads(match.group(1))
if source_map.get('format') != 'phpefc-c-source-lines-v0':
    raise SystemExit('unexpected source-map format')

mappings = source_map.get('mappings') or []
expected = {
    2: 'FunctionDeclaration',
    3: 'CallStatement',
    4: 'CallStatement',
    6: 'CallStatement',
}
found = {}
for mapping in mappings:
    if mapping.get('phpSourceFile') != src:
        continue
    php_line = mapping.get('phpLine')
    kind = mapping.get('kind')
    if php_line in expected and kind == expected[php_line]:
        found[php_line] = mapping

missing = [line for line in expected if line not in found]
if missing:
    raise SystemExit('missing function source-map entries for PHP line(s): ' + ', '.join(map(str, missing)) + '\n' + json.dumps(mappings, indent=2))

# Return the Vala line for the function-body throw; the shell uses it to verify
# phpefc-c-add-source-lines rewrites a Valac-style #line marker to PHP line 4.
print(found[4]['valaLine'])
PY
)

cat > "$fake_c" <<C
#line $map_info "$(basename "$vala")"
void synthetic_function_body_line(void) {}
C

"$c_add_source_lines" "$fake_c" "$mapped_c" "$vala" "$debug_bundle"

expected_line="#line 4 \"$src\""
if ! grep -Fq "$expected_line" "$mapped_c"; then
    printf 'expected mapped C to contain: %s\n' "$expected_line" >&2
    printf 'generated Vala:\n' >&2
    cat "$vala" >&2
    printf 'mapped C:\n' >&2
    cat "$mapped_c" >&2
    exit 1
fi

if ! grep -Fq '"rewrittenLineMarkers": 1' "$debug_bundle"; then
    printf 'expected debug bundle to report one rewritten line marker\n' >&2
    cat "$debug_bundle" >&2
    exit 1
fi

printf 'ok 1 - function body lines are present in PHPEFC-C-SOURCE-LINES and rewrite to PHP source lines\n'
