#!/usr/bin/env bash
set -euo pipefail
bin=$1
work=${MESON_TEST_TMPDIR:-}
if [ -z "$work" ]; then
    work=$(mktemp -d)
    trap 'rm -rf "$work"' EXIT
fi

run_case() {
    local mode=$1
    local stdout="$work/${mode}.stdout.txt"
    local stderr="$work/${mode}.stderr.txt"
    set +e
    "$bin" "$mode" >"$stdout" 2>"$stderr"
    local status=$?
    set -e
    if [ "$status" -ne 255 ]; then
        echo "[$mode] expected exit status 255, got $status" >&2
        cat "$stdout" >&2
        cat "$stderr" >&2
        exit 1
    fi
}

run_zero_case() {
    local mode=$1
    local stdout="$work/${mode}.stdout.txt"
    local stderr="$work/${mode}.stderr.txt"
    set +e
    "$bin" "$mode" >"$stdout" 2>"$stderr"
    local status=$?
    set -e
    if [ "$status" -ne 0 ]; then
        echo "[$mode] expected exit status 0, got $status" >&2
        cat "$stdout" >&2
        cat "$stderr" >&2
        exit 1
    fi
}

run_case_with_stripped_runtime_core() {
    local mode=$1
    local runtime_core_lib
    runtime_core_lib=$(ldd "$bin" | awk '/libphpef-runtime-core[.]so/ { print $3; exit }')
    if [ -z "$runtime_core_lib" ] || [ ! -f "$runtime_core_lib" ]; then
        echo "[$mode] could not find linked libphpef-runtime-core.so for stripped runtime test" >&2
        ldd "$bin" >&2 || true
        exit 1
    fi
    local stripped_dir="$work/stripped-runtime-core"
    mkdir -p "$stripped_dir"
    cp "$runtime_core_lib" "$stripped_dir/libphpef-runtime-core.so"
    strip --strip-unneeded "$stripped_dir/libphpef-runtime-core.so"

    local stdout="$work/${mode}-stripped-runtime.stdout.txt"
    local stderr="$work/${mode}-stripped-runtime.stderr.txt"
    set +e
    LD_LIBRARY_PATH="$stripped_dir:${LD_LIBRARY_PATH:-}" "$bin" "$mode" >"$stdout" 2>"$stderr"
    local status=$?
    set -e
    if [ "$status" -ne 255 ]; then
        echo "[$mode stripped runtime-core] expected exit status 255, got $status" >&2
        cat "$stdout" >&2
        cat "$stderr" >&2
        exit 1
    fi
}

run_zero_case optimized-aliases

run_case stripped-summary
stripped_summary_stderr="$work/stripped-summary.stderr.txt"
if ! grep -Fq "no stacktrace available, involved libraries:" "$stripped_summary_stderr"; then
    echo 'stripped stacktrace did not report unavailable stacktrace summary' >&2
    cat "$stripped_summary_stderr" >&2
    exit 1
fi
for expected_library in "#1 /tmp/hallowelt" "#2 /usr/lib64/libc.so.6" "#3 /tmp/hallowelt"; do
    if ! grep -Fq "$expected_library" "$stripped_summary_stderr"; then
        echo "stripped stacktrace summary missed $expected_library" >&2
        cat "$stripped_summary_stderr" >&2
        exit 1
    fi
done
if grep -Fq "in '??'" "$stripped_summary_stderr"; then
    echo 'raw unknown stacktrace frames leaked into stripped summary' >&2
    cat "$stripped_summary_stderr" >&2
    exit 1
fi


# Direct helper/unregistered frames are intentionally not asserted here: depending on
# the compiler/stacktrace backend they may collapse to main before PHPEF can normalize
# them. The stable runtime contract is the registered PHP function/static-method path.

run_case registered
registered_stderr="$work/registered.stderr.txt"
if ! grep -Fq "in 'foo'" "$registered_stderr"; then
    echo 'registered handler was not normalized to the PHP function name' >&2
    cat "$registered_stderr" >&2
    exit 1
fi
foo_count=$(grep -Fc "in 'foo'" "$registered_stderr")
if [ "$foo_count" -ne 1 ]; then
    echo "registered handler appeared $foo_count times; expected exactly one logical PHP frame" >&2
    cat "$registered_stderr" >&2
    exit 1
fi
if grep -Fq "phpef_file_example_php__registered" "$registered_stderr"; then
    echo 'registered handler symbol leaked into normalized stacktrace' >&2
    cat "$registered_stderr" >&2
    exit 1
fi
if grep -Eq "in 'foo' at .*\.c:" "$registered_stderr"; then
    echo 'registered native handler frame was half-normalized to PHP name with C location' >&2
    cat "$registered_stderr" >&2
    exit 1
fi
if grep -Fq "phpef_runtime_core_call_function" "$registered_stderr"; then
    echo 'runtime-core call dispatcher frame leaked into PHP stacktrace' >&2
    cat "$registered_stderr" >&2
    exit 1
fi

run_case registered-method
registered_method_stderr="$work/registered-method.stderr.txt"
if ! grep -Fq "in 'testclass::testfunc'" "$registered_method_stderr"; then
    echo 'registered static method handler was not normalized to class::method' >&2
    cat "$registered_method_stderr" >&2
    exit 1
fi
method_count=$(grep -Fc "in 'testclass::testfunc'" "$registered_method_stderr")
if [ "$method_count" -ne 1 ]; then
    echo "registered static method appeared $method_count times; expected exactly one logical PHP frame" >&2
    cat "$registered_method_stderr" >&2
    exit 1
fi
if grep -Fq "phpef_classes_php__testclass.testfunc" "$registered_method_stderr" || grep -Fq "phpef_classes_php__testclass_testfunc" "$registered_method_stderr"; then
    echo 'registered static method handler symbol leaked into normalized stacktrace' >&2
    cat "$registered_method_stderr" >&2
    exit 1
fi
if grep -Fq "phpef_runtime_core_call_static_method" "$registered_method_stderr"; then
    echo 'runtime-core static method dispatcher frame leaked into PHP stacktrace' >&2
    cat "$registered_method_stderr" >&2
    exit 1
fi

run_case_with_stripped_runtime_core missing-function
missing_function_stripped_stderr="$work/missing-function-stripped-runtime.stderr.txt"
if ! grep -Fq "Call to undefined function missing_function()" "$missing_function_stripped_stderr"; then
    echo 'stripped runtime-core missing-function stacktrace lost the fatal error message' >&2
    cat "$missing_function_stripped_stderr" >&2
    exit 1
fi
if grep -Fq "phpef_runtime_core_" "$missing_function_stripped_stderr"; then
    echo 'stripped runtime-core internal frame leaked into PHP stacktrace' >&2
    cat "$missing_function_stripped_stderr" >&2
    exit 1
fi

printf 'ok 1 - stacktrace names use only registered functions/static methods or explicit frame metadata\n'
