#!/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
src=$2
valac_bin=${3:-valac}
expected_line=${4:-7}
bad_line=${5:-4}
expected_frame=${6:-}

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

for tool in "$php2ast" "$phpast2phpir" "$phpir2valair" "$valair2vala" "$c_add_source_lines" "$valac_bin"; do
    if ! command -v "$tool" >/dev/null 2>&1 && [ ! -x "$tool" ]; then
        echo "missing 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/nested_runtime.phpast"
phpir="$work/nested_runtime.phpir"
valair="$work/nested_runtime.valair"
vala="$work/nested_runtime.vala"
c_file="$work/nested_runtime.c"
mapped_c="$work/nested_runtime.mapped.c"
debug_bundle="$work/nested_runtime.debug.json"
bin="$work/nested-runtime"
out="$work/nested-runtime.out"

"$php2ast" "$src" "$phpast" >/dev/null
"$phpast2phpir" "$phpast" "$phpir" >/dev/null
"$phpir2valair" "$phpir" "$valair" >/dev/null
"$valair2vala" "$valair" "$vala" >/dev/null

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_VAPIDIR:-}" ]; then
    valac_extra_args+=("--vapidir=$PHPEF_RUNTIME_VAPIDIR")
else
    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
fi

"$valac_bin" --debug -C "${valac_extra_args[@]}" "${runtime_pkg_args[@]}" --directory "$work" "$vala" >/dev/null
if [ ! -f "$c_file" ]; then
    actual_c=$(find "$work" -maxdepth 1 -type f -name '*.c' | head -n 1 || true)
    if [ -z "$actual_c" ]; then
        echo "valac did not generate C source" >&2
        exit 1
    fi
    c_file="$actual_c"
fi

"$c_add_source_lines" "$c_file" "$mapped_c" "$vala" "$debug_bundle" >/dev/null
cc -g -o "$bin" "$mapped_c" $(pkg-config --cflags --libs ${runtime_pkg_args[@]/--pkg/})

set +e
"$bin" >"$out" 2>&1
rc=$?
set -e

if [ "$rc" -eq 0 ]; then
    echo "expected generated binary to fail with UnexpectedValueException" >&2
    cat "$out" >&2
    exit 1
fi

expected="at $src:$expected_line"
if ! grep -Fq "$expected" "$out"; then
    echo "expected runtime stacktrace to contain: $expected" >&2
    cat "$out" >&2
    exit 1
fi

if [ -n "$bad_line" ] && grep -Fq "at $src:$bad_line" "$out"; then
    echo "runtime stacktrace regressed to wrong source line" >&2
    cat "$out" >&2
    exit 1
fi

if [ -n "$expected_frame" ]; then
    expected_frame_text="in '$expected_frame' at $src:$expected_line"
    if ! grep -Fq "$expected_frame_text" "$out"; then
        echo "expected runtime stacktrace to contain PHP frame name: $expected_frame_text" >&2
        cat "$out" >&2
        exit 1
    fi
    if grep -Fq "phpef_" "$out"; then
        echo "runtime stacktrace leaked generated PHPEF symbol name" >&2
        cat "$out" >&2
        exit 1
    fi
fi

printf 'ok 1 - runtime stacktrace maps nested foreach/if throw to PHP throw line and display name\n'
