#!/usr/bin/env bash
set -euo pipefail
runtime_pkg_args=(--pkg phpef-runtime-core --pkg phpef-runtime-embed)
if [ -n "${PHPEF_RUNTIME_NATIVE_PACKAGES:-}" ]; then
    old_ifs=$IFS; IFS=:
    for native_pkg in $PHPEF_RUNTIME_NATIVE_PACKAGES; do
        [ -n "$native_pkg" ] && runtime_pkg_args+=(--pkg "$native_pkg")
    done
    IFS=$old_ifs
elif [ -n "${PHPEF_RUNTIME_NATIVE_VAPIS:-}" ]; then
    old_ifs=$IFS; IFS=:
    for native_vapi in $PHPEF_RUNTIME_NATIVE_VAPIS; do
        [ -n "$native_vapi" ] || continue
        native_pkg=$(basename "$native_vapi" .vapi)
        runtime_pkg_args+=(--pkg "$native_pkg")
    done
    IFS=$old_ifs
fi

build_root=$1
export LD_LIBRARY_PATH="$build_root/src/lib:$build_root/src/cli:${LD_LIBRARY_PATH:-}"
test_dir=$2
php_bin=${3:-php}
valac_bin=${4:-valac}
mode=${5:-optimized-faster}

case "$mode" in
    optimized-faster|no-optimizer-slower) ;;
    *)
        echo "unknown performance guard mode: $mode" >&2
        exit 2
        ;;
esac

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_typing="$cli_dir/phpefc-valair-optimize-typing"
valair_optimize_library="$cli_dir/phpefc-valair-optimize-library"
valair_optimize_fastpath_runtime="$cli_dir/phpefc-valair-optimize-fastpath-runtime"

required_tools=("$php_bin" "$valac_bin" "$php2ast" "$phpast2phpir" "$phpir2valair" "$valair2vala")
if [ "$mode" = "optimized-faster" ]; then
    required_tools+=("$valair_optimize_typing" "$valair_optimize_library" "$valair_optimize_fastpath_runtime")
fi
for tool in "${required_tools[@]}"; do
    if ! command -v "$tool" >/dev/null 2>&1 && [ ! -x "$tool" ]; then
        echo "missing tool: $tool" >&2
        exit 99
    fi
done

if [ ! -f "$test_dir/main.php" ]; then
    echo "missing performance fixture: $test_dir/main.php" >&2
    exit 2
fi

work=${MESON_TEST_TMPDIR:-}
if [ -z "$work" ]; then
    work=$(mktemp -d)
    trap 'rm -rf "$work"' EXIT
fi
mkdir -p "$work/src" "$work/build"
cp -R "$test_dir"/. "$work/src"/

php_out="$work/php.out"
phpefc_out="$work/phpefc.out"

set +e
(
    cd "$work/src"
    "$php_bin" main.php
) >"$php_out" 2>&1
php_rc=$?
set -e
if [ "$php_rc" -ne 0 ]; then
    echo "PHP CLI benchmark failed with exit code $php_rc" >&2
    cat "$php_out" >&2
    exit 1
fi

(
    cd "$work/src"
    "$php2ast" main.php "$work/build/main.phpast"
    "$phpast2phpir" "$work/build/main.phpast" "$work/build/main.phpir"
    "$phpir2valair" "$work/build/main.phpir" "$work/build/main.valair"
    if [ "$mode" = "optimized-faster" ]; then
        "$valair_optimize_typing" --suppress-warning "$work/build/main.valair" "$work/build/main.valair.2.afteropt.typing-zval2static"
        "$valair_optimize_fastpath_runtime" "$work/build/main.valair.2.afteropt.typing-zval2static" "$work/build/main.valair.3.afteropt.fastpath-runtime"
        "$valair_optimize_library" "$work/build/main.valair.3.afteropt.fastpath-runtime" "$work/build/main.valair.4.afteropt.library-embed2native"
        "$valair_optimize_typing" "$work/build/main.valair.4.afteropt.library-embed2native" "$work/build/main.valair.5.afteropt.typing-zval2static-final"
        valair_input="$work/build/main.valair.5.afteropt.typing-zval2static-final"
    else
        valair_input="$work/build/main.valair"
    fi
    "$valair2vala" "$valair_input" "$work/build/main.vala"

    valac_extra_args=()
    if [ -n "${PHPEF_RUNTIME_DEV_LIBDIR:-}" ]; then
        valac_extra_args+=("-X" "-Wl,-rpath,$PHPEF_RUNTIME_DEV_LIBDIR")
    fi
    if [ -n "${PHPEF_RUNTIME_CORE_VAPI:-}" ]; then
        valac_extra_args+=("--vapidir=$(dirname "$PHPEF_RUNTIME_CORE_VAPI")")
    fi
    if [ -n "${PHPEF_RUNTIME_EMBED_VAPI:-}" ]; then
        valac_extra_args+=("--vapidir=$(dirname "$PHPEF_RUNTIME_EMBED_VAPI")")
    fi
    if [ -n "${PHPEF_RUNTIME_NATIVE_VAPIS:-}" ]; then
        old_ifs=$IFS; IFS=:
        for native_vapi in $PHPEF_RUNTIME_NATIVE_VAPIS; do
            [ -n "$native_vapi" ] || continue
            valac_extra_args+=("--vapidir=$(dirname "$native_vapi")")
        done
        IFS=$old_ifs
    fi
    "$valac_bin" "${valac_extra_args[@]}" "${runtime_pkg_args[@]}" "$work/build/main.vala" -o "$work/build/phpefc-main"
) >"$work/phpefc.compile" 2>&1 || {
    echo "PHPEFC benchmark compile failed for mode $mode" >&2
    cat "$work/phpefc.compile" >&2
    exit 1
}

set +e
(
    cd "$work/src"
    "$work/build/phpefc-main"
) >"$phpefc_out" 2>&1
phpefc_rc=$?
set -e
if [ "$phpefc_rc" -ne 0 ]; then
    echo "PHPEFC benchmark failed with exit code $phpefc_rc for mode $mode" >&2
    cat "$phpefc_out" >&2
    exit 1
fi

set +e
python3 - "$mode" "$php_out" "$phpefc_out" <<'PY'
import re
import sys

labels = [
    "Benchmark 10 run",
    "Benchmark 20 run",
    "Benchmark 10 tuned run",
    "Benchmark 20 tuned run",
]

def parse(path):
    values = {}
    pattern = re.compile(r'^(Benchmark (?:10|20)(?: tuned)? run):\s*([0-9][0-9,]*)/sec')
    with open(path, 'r', encoding='utf-8', errors='replace') as fh:
        for line in fh:
            m = pattern.search(line.strip())
            if m:
                values[m.group(1)] = int(m.group(2).replace(',', ''))
    missing = [label for label in labels if label not in values]
    if missing:
        raise SystemExit(f"missing benchmark lines in {path}: {missing}")
    return values

mode = sys.argv[1]
php = parse(sys.argv[2])
phpefc = parse(sys.argv[3])
failed = []

if mode == "optimized-faster":
    print("optimized PHPEFC vs PHP CLI Fibonacci benchmark guard:")
    for label in labels:
        delta = phpefc[label] - php[label]
        passed = phpefc[label] > php[label]
        relation = "PASS" if passed else "FAIL"
        print(f"{relation}: {label}: PHP={php[label]:,}/sec PHPEFC={phpefc[label]:,}/sec delta={delta:,}/sec")
        if not passed:
            failed.append(label)
    if failed:
        print("FAIL - PHPEFC optimized Fibonacci must be faster than PHP CLI in all 4 measurements; failing: " + ", ".join(failed), file=sys.stderr)
        raise SystemExit(1)
elif mode == "no-optimizer-slower":
    print("unoptimized PHPEFC vs PHP CLI Fibonacci benchmark guard:")
    for label in labels:
        delta = phpefc[label] - php[label]
        passed = phpefc[label] < php[label]
        relation = "PASS" if passed else "FAIL"
        print(f"{relation}: {label}: PHP={php[label]:,}/sec PHPEFC={phpefc[label]:,}/sec delta={delta:,}/sec")
        if not passed:
            failed.append(label)
    if failed:
        print("FAIL - PHPEFC without optimizers must be slower than PHP CLI in all 4 measurements; failing: " + ", ".join(failed), file=sys.stderr)
        raise SystemExit(1)
else:
    raise SystemExit(f"unknown mode: {mode}")
PY
rc=$?
set -e
exit "$rc"
