#!/bin/sh
set -eu

PHP2VALA=$1
if [ -z "$PHP2VALA" ]; then
    echo "php2vala binary missing" >&2
    exit 1
fi
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
RUNTIME_BUILD=$(CDPATH= cd -- "$SCRIPT_DIR/../../../a_vala_libs/valaphp-runtime-embed/build" 2>/dev/null && pwd || true)
if [ -n "$RUNTIME_BUILD" ]; then
    LD_LIBRARY_PATH="$RUNTIME_BUILD:${LD_LIBRARY_PATH:-}"
    export LD_LIBRARY_PATH
fi

TMPDIR=$(mktemp -d /tmp/php2vala-regressions.XXXXXX)
trap 'rm -rf "$TMPDIR"' EXIT

run_php2vala() {
    name=$1
    shift 1
    "$PHP2VALA" "$@" "$TMPDIR/$name.php" "$TMPDIR/$name.vala" >"$TMPDIR/$name.out" 2>"$TMPDIR/$name.err"
}

assert_contains() {
    file=$1
    pattern=$2
    if ! grep -F "$pattern" "$file" >/dev/null 2>&1; then
        echo "missing pattern in $file: $pattern" >&2
        echo "--- $file ---" >&2
        sed -n '1,220p' "$file" >&2 || true
        exit 1
    fi
}
assert_not_contains() {
    file=$1
    pattern=$2
    if grep -F "$pattern" "$file" >/dev/null 2>&1; then
        echo "unexpected pattern in $file: $pattern" >&2
        echo "--- $file ---" >&2
        sed -n '1,220p' "$file" >&2 || true
        exit 1
    fi
}

cat >"$TMPDIR/quoted_paren_concat.php" <<'PHP'
<?php
$a = 1;
echo "Hallo (".$a.") World\r\n";
PHP
run_php2vala quoted_paren_concat --both-runtimes --no-optimize-local-vars
assert_contains "$TMPDIR/quoted_paren_concat.vala" 'Php.concat_many (Php.zval.string_value ("Hallo (")'
assert_not_contains "$TMPDIR/quoted_paren_concat.err" "PHP function 'Hallo'"
assert_not_contains "$TMPDIR/quoted_paren_concat.err" 'trying native zval'
assert_not_contains "$TMPDIR/quoted_paren_concat.err" 'trying embed static'

cp "$TMPDIR/quoted_paren_concat.php" "$TMPDIR/quoted_paren_concat_static.php"
run_php2vala quoted_paren_concat_static --embed-runtime --optimize-local-vars
assert_contains "$TMPDIR/quoted_paren_concat_static.vala" 'PhpEmbed.echo_static ("Hallo (" + a.to_string () + ") World\r\n"'
assert_not_contains "$TMPDIR/quoted_paren_concat_static.vala" 'Php.zval_to_string (Php.concat_many'
assert_not_contains "$TMPDIR/quoted_paren_concat_static.vala" 'Php.zval.integer (a)'

cat >"$TMPDIR/comment_paren_vars.php" <<'PHP'
<?php
// Test1 - optimizing local-func-vars (main)
$a = 1;
echo $a;
// Test 2 - optimizing local-func-vars (function)
// Test 3 - optimizing local-func-vars (method static)
// Test 4 - optimizing local-func-vars (method object)
PHP
run_php2vala comment_paren_vars --embed-runtime --optimize-cross-file-func-vars
assert_not_contains "$TMPDIR/comment_paren_vars.err" "PHP function 'vars'"
assert_not_contains "$TMPDIR/comment_paren_vars.err" 'falling back to zval'
cat >"$TMPDIR/multiline_concat.php" <<'PHP'
<?php
function usage(): void {
    $out = fopen('php://stdout', 'w');
    fwrite($out, "Usage\n" .
        "Options\n" .
        "Done\n");
}
usage();
PHP
run_php2vala multiline_concat --both-runtimes
assert_contains "$TMPDIR/multiline_concat.ast.txt" 'fwrite($out, "Usage\\n" .'
assert_contains "$TMPDIR/multiline_concat.vala" 'Usage\n" + "Options\n" + "Done\n'

cat >"$TMPDIR/closure_interpolation_case.php" <<'PHP'
<?php
function usage(int $code = 0): void { exit($code); }
function parse_args(array $argv): array {
    $i = 1;
    $arg = $argv[$i];
    $next = function () use ($argv, &$i, $arg): string {
        if (!isset($argv[$i + 1])) {
            fwrite(fopen('php://stderr', 'w'), "missing value for {$arg}\n");
            exit(2);
        }
        return $argv[++$i];
    };
    switch ($arg) {
        case '-h':
        case '--help':
            usage(0);
            break;
        default:
            usage(2);
    }
    return [];
}
parse_args($argv);
PHP
run_php2vala closure_interpolation_case --both-runtimes
assert_contains "$TMPDIR/closure_interpolation_case.ast.txt" "case '--help':"
assert_contains "$TMPDIR/closure_interpolation_case.vala" 'case "--help":'
assert_contains "$TMPDIR/closure_interpolation_case.vala" '__php2vala_zval_closure next'

cat >"$TMPDIR/do_while.php" <<'PHP'
<?php
$i = 0;
do {
    $i++;
} while ($i < 2);
PHP
run_php2vala do_while --both-runtimes
assert_contains "$TMPDIR/do_while.ast.txt" '} while ($i < 2);'
assert_contains "$TMPDIR/do_while.vala" '} while (i < 2);'

cat >"$TMPDIR/zend_scopes.php" <<'PHP'
<?php
function hello($name) {
    echo "Hello $name\n";
}
class DemoClass {
    public function method($name) {
        echo "Class $name\n";
    }
}
hello('Sebastian');
$demo = new DemoClass();
$demo->method('Sebastian');
PHP
run_php2vala zend_scopes --both-runtimes
assert_contains "$TMPDIR/zend_scopes.zend_op_array.txt" 'op_array function:hello'
assert_contains "$TMPDIR/zend_scopes.zend_op_array.txt" 'op_array class:DemoClass::method'
assert_contains "$TMPDIR/zend_scopes.zend_op_array.txt" 'literal=string(len=6 value="Hello ")'
assert_contains "$TMPDIR/zend_scopes.zend_op_array.txt" 'literal=string(len=6 value="Class ")'
assert_contains "$TMPDIR/zend_scopes.zend_match.txt" 'function:hello'
assert_contains "$TMPDIR/zend_scopes.zend_match.txt" 'class:DemoClass::method'

cat >"$TMPDIR/native_defaults.php" <<'PHP'
<?php
$data = [];
$data['timestamp'] = date('Y-m-d H:i:s');
PHP
run_php2vala native_defaults --both-runtimes --optimize-cross-file-func-vars
assert_contains "$TMPDIR/native_defaults.vala" 'PhpNative.time_static ("'
if grep -F 'php_file' "$TMPDIR/native_defaults.vala" >/dev/null 2>&1; then
    echo 'unexpanded php_file in generated native default' >&2
    sed -n '1,180p' "$TMPDIR/native_defaults.vala" >&2
    exit 1
fi


cat >"$TMPDIR/zval_short_arrays_and_dir.php" <<'PHP'
<?php
class DemoArrayConsumer {
    public function __construct($items) {}
}
function read_power() {
    return [
        'voltage_v' => 52.48,
        'remain_ah' => 83.8,
    ];
}
$demo = new DemoArrayConsumer([
    'address' => 'US2000C',
]);
$pwr = read_power();
$checksum = (int)($pwr['voltage_v'] * 10) + (int)($pwr['remain_ah'] * 10);
$path = __DIR__ . '/parts';
echo $checksum . ':' . $path . "\n";
PHP
run_php2vala zval_short_arrays_and_dir --both-runtimes
assert_contains "$TMPDIR/zval_short_arrays_and_dir.vala" 'demo.__construct (__php2vala_array_'
assert_contains "$TMPDIR/zval_short_arrays_and_dir.vala" 'return __php2vala_array_'
assert_contains "$TMPDIR/zval_short_arrays_and_dir.vala" 'Php.zval_to_int (Php.mul_zval ('
assert_contains "$TMPDIR/zval_short_arrays_and_dir.vala" 'Php.zval.string_value ("/tmp/php2vala-regressions.'
assert_contains "$TMPDIR/zval_short_arrays_and_dir.vala" 'Php.zval.string_value ("/parts")'

cat >"$TMPDIR/native_array_filter_lowering.php" <<'PHP'
<?php
$values = [900, 1000, 2500, 5001];
$data = array_filter([
    'voltage_mv' => 52000,
    'current_ma' => null,
], fn($v) => $v !== null);
$cellVoltages = array_values(array_filter(
    array_slice($values, 1),
    fn($value) => $value >= 1000 && $value <= 5000
));
PHP
run_php2vala native_array_filter_lowering --native-runtime --optimize-cross-file-func-vars
assert_not_contains "$TMPDIR/native_array_filter_lowering.err" "native-runtime is missing bindings"
assert_not_contains "$TMPDIR/native_array_filter_lowering.err" "PHP function 'array_filter'"
assert_not_contains "$TMPDIR/native_array_filter_lowering.err" "PHP function 'array_values'"
assert_not_contains "$TMPDIR/native_array_filter_lowering.vala" "PhpEmbed"
assert_not_contains "$TMPDIR/native_array_filter_lowering.vala" "array_filter ("
assert_not_contains "$TMPDIR/native_array_filter_lowering.vala" "array_values_zval"
assert_contains "$TMPDIR/native_array_filter_lowering.vala" "Php.array_values"

cat >"$TMPDIR/user_function_runtime_probe.php" <<'PHP'
<?php
function test_func($a) {
    echo "Hallo (".$a.") World\r\n";
}
test_func(2);
PHP
run_php2vala user_function_runtime_probe --embed-runtime --optimize-cross-file-func-vars
assert_contains "$TMPDIR/user_function_runtime_probe.vala" "__php2vala_file_func_test_func"
assert_not_contains "$TMPDIR/user_function_runtime_probe.err" "PHP function 'test_func'"
assert_not_contains "$TMPDIR/user_function_runtime_probe.err" "falling back to zval"


cat >"$TMPDIR/dynamic_recast_compound_ops.php" <<'PHP'
<?php
$var = "hallo";
$var = 2;
$var++;
echo "Hallo1 [".$var."]\r\n";
$var--;
echo "Hallo2 [".$var."]\r\n";
$var*=4;
echo "Hallo3 [".$var."]\r\n";
$var/=2;
echo "Hallo4 [".$var."]\r\n";
PHP
run_php2vala dynamic_recast_compound_ops --embed-runtime --optimize-cross-file-func-vars
assert_contains "$TMPDIR/dynamic_recast_compound_ops.vala" "Php.zval var_zval = Php.add_zval"
assert_contains "$TMPDIR/dynamic_recast_compound_ops.vala" "var_zval = Php.sub_zval"
assert_contains "$TMPDIR/dynamic_recast_compound_ops.vala" "var_zval = Php.mul_zval"
assert_contains "$TMPDIR/dynamic_recast_compound_ops.vala" "var_zval = Php.div_zval"
assert_not_contains "$TMPDIR/dynamic_recast_compound_ops.vala" "Php.zval var ="
assert_not_contains "$TMPDIR/dynamic_recast_compound_ops.vala" "var = Php"

echo "php2vala regressions ok"
