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

included_txt=$1
generated_vala=$2
public_vapi=$3
call_c=$4
not_included_txt=$5
inventory_bin=$6
php_function_extensions_csv=${7:-}

has_php_function_extension() {
    local needle=$1
    [[ ",${php_function_extensions_csv}," == *",${needle},"* || ",${php_function_extensions_csv}," == *",all,"* || ",${php_function_extensions_csv}," == *",*,"* ]]
}

if grep -E '^function[[:space:]].*(^|[[:space:]])callable($|[[:space:]])' "$included_txt"; then
    echo "included inventory must not contain a callable header/column" >&2
    exit 1
fi

grep -Fq 'function_exists (as zendcall_function_exists)' "$included_txt"
grep -Fq 'class_exists (as zendcall_class_exists)' "$included_txt"
grep -Fq 'substr' "$included_txt"
grep -Fq '# typed_function_count=' "$included_txt"
grep -Fq 'typed' "$included_txt"
grep -Eq '^strlen[[:space:]]+phpfunc_strlen[[:space:]]+1[[:space:]]+1[[:space:]]+no[[:space:]]+X[[:space:]]+int' "$included_txt"
grep -Eq '^gethostbyname[[:space:]]+phpfunc_gethostbyname[[:space:]]+1[[:space:]]+1[[:space:]]+no[[:space:]]+X[[:space:]]+string' "$included_txt"

python3 - "$included_txt" <<'PY'
import sys
path = sys.argv[1]
wrapper_col = None
section = None
with open(path, encoding='utf-8') as fh:
    for lineno, raw in enumerate(fh, 1):
        line = raw.rstrip('\n')
        if not line or line.startswith('#'):
            continue
        if line.startswith('['):
            section = line
            wrapper_col = None
            continue
        if line.startswith('function') and 'wrapper' in line:
            wrapper_col = line.index('wrapper')
            continue
        if line.startswith('---'):
            continue
        if wrapper_col is None:
            continue
        if len(line) <= wrapper_col or not line[wrapper_col:].startswith('phpfunc_'):
            raise SystemExit(f'{path}:{lineno}: wrapper column is not aligned in {section}: {line!r}')
print('ok - wrapper columns are aligned with rendered display names')
PY

for symbol in phpfunc_zendcall_function_exists phpfunc_zendcall_class_exists phpfunc_substr; do
    grep -Fq "$symbol" "$generated_vala"
    grep -Fq "$symbol" "$public_vapi"
done

for static_symbol in phpfunc_strlen_typed_int_arg1_string phpfunc_gethostbyname_typed_string_arg1_string; do
    grep -Fq "$static_symbol" "$generated_vala"
    grep -Fq "$static_symbol" "$public_vapi"
done

grep -Fq 'return call_php_function_typed_int_arg1_string("strlen", string_arg);' "$generated_vala"
grep -Fq 'return call_php_function_typed_string_arg1_string("gethostbyname", hostname);' "$generated_vala"
if grep -Fq 'Zval.from_' "$generated_vala"; then
    echo "generated typed wrappers must not perform Vala-side Zval.from_* conversion" >&2
    exit 1
fi

grep -Fq '// PHPEF typed_fast_path static_php_call; source php_function; PHP function: strlen; typed_signature _typed_int_arg1_string; boundary call_php_function_typed_int_arg1_string' "$public_vapi"
grep -Fq '// PHPEF typed_fast_path static_php_call; source php_function; PHP function: gethostbyname; typed_signature _typed_string_arg1_string; boundary call_php_function_typed_string_arg1_string' "$public_vapi"

for native_symbol in phpfunc_echo_typed_void_arg1_string phpfunc_print_typed_int_arg1_string; do
    grep -Fq "$native_symbol" "$public_vapi"
done

grep -Fq '// PHPEF typed_fast_path native; source language_construct; PHP construct: echo; typed_signature _typed_void_arg1_string' "$public_vapi"
grep -Fq '// PHPEF typed_fast_path native; source language_construct; PHP construct: print; typed_signature _typed_int_arg1_string' "$public_vapi"

grep -Fq '// PHP standard: substr' "$public_vapi"
if has_php_function_extension ctype; then
    grep -Fq '// PHP ctype: ctype_digit' "$public_vapi"
    grep -Fq 'phpfunc_ctype_digit' "$generated_vala"
    grep -Fq 'phpfunc_ctype_digit' "$public_vapi"
else
    if grep -Fq 'phpfunc_ctype_digit' "$generated_vala" || grep -Fq 'phpfunc_ctype_digit' "$public_vapi"; then
        echo "ctype_digit wrapper must not be generated when ctype is not part of php_function_extensions" >&2
        exit 1
    fi
fi
grep -Fq '// PHP pcre: preg_match; by_ref_arg_indexes 2' "$public_vapi"
grep -Fq '// PHP pcre: preg_replace; by_ref_arg_indexes 4' "$public_vapi"
grep -Fq '// PHP Core: function_exists (as zendcall_function_exists); wrapper phpfunc_zendcall_function_exists' "$public_vapi"

if [[ $(grep -Fc 'annotated by phpef-runtime-embed function inventory postprocess' "$public_vapi") -ne 1 ]]; then
    echo "VAPI postprocess header annotation must appear exactly once" >&2
    exit 1
fi
python3 - "$public_vapi" <<'PYCHECK'
import sys
path = sys.argv[1]
annotation_text = 'annotated by phpef-runtime-embed function inventory postprocess'
with open(path, encoding='utf-8') as fh:
    lines = [line.rstrip('\n') for line in fh]
for index, line in enumerate(lines):
    if ' generated by valac ' in line:
        if line.lstrip().startswith('/*') and line.rstrip().endswith('*/'):
            expected = line[:len(line) - len(line.lstrip())] + f'/* {annotation_text} */'
        elif line.lstrip().startswith('//'):
            expected = line[:len(line) - len(line.lstrip())] + f'// {annotation_text}'
        else:
            raise SystemExit(f'unsupported VAPI valac-generated comment style: {line!r}')
        if index + 1 >= len(lines) or lines[index + 1] != expected:
            raise SystemExit('VAPI postprocess header annotation is not directly after the valac-generated line with matching comment style')
        print('ok - VAPI postprocess header annotation follows valac-generated line with matching comment style')
        break
else:
    raise SystemExit('VAPI valac-generated header line not found')
PYCHECK

if [[ $(grep -Fc '// PHPEF_RUNTIME_EMBED_EXCLUDED_FUNCTIONS_BEGIN v1' "$public_vapi") -ne 1 ]]; then
    echo "VAPI excluded-functions block begin marker must appear exactly once" >&2
    exit 1
fi
if [[ $(grep -Fc '// PHPEF_RUNTIME_EMBED_EXCLUDED_FUNCTIONS_END' "$public_vapi") -ne 1 ]]; then
    echo "VAPI excluded-functions block end marker must appear exactly once" >&2
    exit 1
fi

python3 - "$public_vapi" <<'PY'
import json
import sys
path = sys.argv[1]
in_block = False
entries = {}
with open(path, encoding='utf-8') as fh:
    for raw in fh:
        line = raw.rstrip('\n')
        if line == '// PHPEF_RUNTIME_EMBED_EXCLUDED_FUNCTIONS_BEGIN v1':
            in_block = True
            continue
        if line == '// PHPEF_RUNTIME_EMBED_EXCLUDED_FUNCTIONS_END':
            in_block = False
            continue
        if not in_block:
            continue
        if not line.startswith('// '):
            raise SystemExit(f'non-comment line in excluded-functions block: {line!r}')
        item = json.loads(line[3:])
        entries[item['extension']] = item['functions']
if 'curl' not in entries or 'curl_exec' not in entries['curl']:
    raise SystemExit('excluded-functions block lacks expected curl/curl_exec entry')
print('ok - VAPI excluded-functions block is machine-readable JSON comments')
PY

tmp_vapi=$(mktemp)
tmp_stamp=$(mktemp)
tmp_once=$(mktemp)
trap 'rm -f "$tmp_vapi" "$tmp_stamp" "$tmp_once"' EXIT
cp "$public_vapi" "$tmp_vapi"
"$inventory_bin" --annotate-vapi "$included_txt" "$not_included_txt" "$tmp_vapi" "$tmp_stamp"
cp "$tmp_vapi" "$tmp_once"
"$inventory_bin" --annotate-vapi "$included_txt" "$not_included_txt" "$tmp_vapi" "$tmp_stamp"
if [[ $(grep -Fc '// PHPEF_RUNTIME_EMBED_EXCLUDED_FUNCTIONS_BEGIN v1' "$tmp_vapi") -ne 1 ]]; then
    echo "repeated VAPI annotation duplicated excluded-functions block" >&2
    exit 1
fi
cmp -s "$tmp_once" "$tmp_vapi" || {
    echo "repeated VAPI annotation is not idempotent" >&2
    exit 1
}

if grep -REq 'zendcall_[Cc]ore_' "$generated_vala" "$public_vapi" "$included_txt"; then
    echo "unexpected public zendcall_core_/zendcall_Core_ symbol" >&2
    exit 1
fi

if grep -REq 'phpfunc_function_exists([^A-Za-z0-9_]|$)' "$generated_vala" "$public_vapi" "$included_txt"; then
    echo "unexpected plain phpfunc_function_exists for special Core function" >&2
    exit 1
fi

if grep -Fq 'function_exists' "$call_c"; then
    echo "phpef_runtime_embed_call.c still contains a per-function function_exists special case" >&2
    exit 1
fi

printf 'ok - function inventory/wrapper metadata checks passed\n'
