#!/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
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"

for tool in "$php2ast" "$phpast2phpir" "$phpir2valair" "$valair2vala"; do
    [ -x "$tool" ] || { echo "missing built tool: $tool" >&2; exit 99; }
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/constructor-property-promotion.phpast"
phpir="$work/constructor-property-promotion.phpir"
phpir_pretty="$work/constructor-property-promotion.phpir.pretty"
valair="$work/constructor-property-promotion.valair"
vala="$work/constructor-property-promotion.vala"
bin="$work/constructor-property-promotion-bin"
out="$work/out"

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

if ! grep -a -Fq 'private PhpIrFunction::$promotedProperties = array(4)' "$phpir_pretty"; then
    echo 'expected PHP-IR to preserve four constructor promoted properties' >&2
    cat "$phpir_pretty" >&2
    exit 1
fi
for prop in device tcp baud timeout; do
    if ! grep -a -Fq '"'"$prop"'" => "private"' "$phpir_pretty"; then
        echo "expected PHP-IR promoted private property: $prop" >&2
        cat "$phpir_pretty" >&2
        exit 1
    fi
done

"$phpir2valair" "$phpir" "$valair" >/dev/null
"$valair2vala" "$valair" "$vala" >/dev/null

if ! grep -Fq 'public static Zval php_construct(Zval __phpefc_this, Zval[] __phpefc_call_args) throws Error' "$vala"; then
    echo 'expected PHP __construct to lower to safe Vala method php_construct' >&2
    cat "$vala" >&2
    exit 1
fi
if grep -Fq 'public static Zval construct(Zval __phpefc_this, Zval[] __phpefc_call_args)' "$vala"; then
    echo 'PHP __construct must not lower to Vala construct()' >&2
    cat "$vala" >&2
    exit 1
fi
if ! grep -Fq 'PhpefRuntimeCore.register_instance_method("PromotedSample", "__construct", php_construct' "$vala"; then
    echo 'expected PHP constructor registration to keep PHP name __construct and handler php_construct' >&2
    cat "$vala" >&2
    exit 1
fi
for prop in device tcp baud timeout; do
    if ! grep -Fq 'PhpefRuntimeCore.set_property(__phpefc_this, "'"$prop"'", ' "$vala"; then
        echo "expected promoted property assignment in Vala: $prop" >&2
        cat "$vala" >&2
        exit 1
    fi
done

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")")
        done
        IFS=$old_ifs
    fi
fi

"$valac_bin" "${valac_extra_args[@]}" "${runtime_pkg_args[@]}" "$vala" -o "$bin"
"$bin" > "$out"
expected=$'ctor\ndone\n'
actual=$(cat "$out")$'\n'
if [ "$actual" != "$expected" ]; then
    echo 'compiled constructor output differs from expected PHP behavior' >&2
    printf 'expected:\n%s' "$expected" >&2
    printf 'actual:\n%s' "$actual" >&2
    exit 1
fi

printf 'ok - constructor property promotion lowers to php_construct, stores promoted properties, and runs constructor\n'
