#!/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
test_dir=$2
php_bin=$3
valac_bin=$4

src="$test_dir/main.php"
cli_dir="$build_root/src/cli"
php2ast="$cli_dir/phpefc-php2ast"
phpast2phpir="$cli_dir/phpefc-phpast2phpir"
phpir2valair="$cli_dir/phpefc-phpir2valair"
valair_optimize="$cli_dir/phpefc-valair-optimize-typing"
valair2vala="$cli_dir/phpefc-valair2vala"

require_tool() {
    local tool=$1
    if [[ "$tool" == */* ]]; then
        [ -x "$tool" ] || { echo "missing tool: $tool" >&2; exit 99; }
    else
        command -v "$tool" >/dev/null || { echo "missing tool: $tool" >&2; exit 99; }
    fi
}
for tool in "$php_bin" "$valac_bin" "$php2ast" "$phpast2phpir" "$phpir2valair" "$valair_optimize" "$valair2vala"; do
    require_tool "$tool"
done

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

bundle_field() {
    local bundle=$1 field=$2
    php -r '
        $wrapper = unserialize(file_get_contents($argv[1]));
        $field = $argv[2];
        if (!is_array($wrapper) || !array_key_exists($field, $wrapper) || !is_string($wrapper[$field])) {
            fwrite(STDERR, "missing bundle field: " . $field . "\n");
            exit(2);
        }
        echo $wrapper[$field];
    ' "$bundle" "$field"
}

phpast="$work/do-while.phpast"
phpir="$work/do-while.phpir"
phpir_pretty="$work/do-while.phpir.pretty"
valair="$work/do-while.valair"
valair_pretty="$work/do-while.valair.pretty"
opt_valair="$work/do-while.valair.afteropt.typing-zval2static"
vala="$work/do-while.vala"
bin="$work/do-while-bin"
php_out="$work/php.out"
phpefc_out="$work/phpefc.out"

"$php_bin" "$src" >"$php_out"
"$php2ast" "$src" "$phpast" >/dev/null
"$phpast2phpir" "$phpast" "$phpir" >/dev/null
bundle_field "$phpir" pretty >"$phpir_pretty"

if ! grep -a -Fq 'PhpIrWhile' "$phpir_pretty" || ! grep -a -Fq 'postTest = true' "$phpir_pretty"; then
    echo 'expected PhpParser Do_ to lower to PhpIrWhile with postTest=true' >&2
    cat "$phpir_pretty" >&2
    exit 1
fi
if ! grep -a -Fq '__phpefc_break' "$phpir_pretty"; then
    echo 'expected do-while fixture to preserve break in PHP-IR' >&2
    cat "$phpir_pretty" >&2
    exit 1
fi

"$phpir2valair" "$phpir" "$valair" >/dev/null
bundle_field "$valair" pretty >"$valair_pretty"
if ! grep -a -Fq 'WhileStatement' "$valair_pretty" || ! grep -a -Fq 'postTest = true' "$valair_pretty"; then
    echo 'expected Vala-IR while statement to preserve postTest=true' >&2
    cat "$valair_pretty" >&2
    exit 1
fi

"$valair_optimize" "$valair" "$opt_valair" >/dev/null
"$valair2vala" "$opt_valair" "$vala" >/dev/null

if [ "$(grep -c '^[[:space:]]*do {$' "$vala")" -lt 2 ]; then
    echo 'expected generated Vala to contain do-while loops' >&2
    cat "$vala" >&2
    exit 1
fi
if ! grep -Fq '} while (' "$vala"; then
    echo 'expected generated Vala do-while closing condition' >&2
    cat "$vala" >&2
    exit 1
fi
if ! grep -Fq 'break;' "$vala"; then
    echo 'expected generated Vala to preserve break inside do-while' >&2
    cat "$vala" >&2
    exit 1
fi

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")")
        valac_extra_args+=("-X" "-I$(dirname "$PHPEF_RUNTIME_CORE_VAPI")")
    fi
    if [ -n "${PHPEF_RUNTIME_EMBED_VAPI:-}" ]; then
        valac_extra_args+=("--vapidir=$(dirname "$PHPEF_RUNTIME_EMBED_VAPI")")
        valac_extra_args+=("-X" "-I$(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")")
            valac_extra_args+=("-X" "-I$(dirname "$native_vapi")")
        done
        IFS=$old_ifs
    fi
fi

"$valac_bin" "${valac_extra_args[@]}" "${runtime_pkg_args[@]}" "$vala" -o "$bin"
"$bin" >"$phpefc_out"

if ! cmp -s "$php_out" "$phpefc_out"; then
    echo 'do-while PHPEFC output differs from PHP' >&2
    diff -u "$php_out" "$phpefc_out" >&2 || true
    exit 1
fi
if [ "$(cat "$phpefc_out")" != '012' ]; then
    echo 'unexpected do-while fixture output' >&2
    cat "$phpefc_out" >&2
    exit 1
fi

printf '%s\n' 'ok 1 - do-while lowers through PHP-IR, Vala-IR, generated Vala, and runs with break semantics'
