#!/bin/bash

set -u

SOURCE_ROOT=$(git rev-parse --show-toplevel) || exit 1
TMPROOT=$(mktemp -d) || exit 1
PASS=0
FAIL=0

cleanup() {
    local rc=${1:-$?}
    trap - EXIT HUP INT TERM
    chmod -R u+w "$TMPROOT" 2>/dev/null || true
    rm -rf "$TMPROOT"
    exit "$rc"
}
trap 'cleanup $?' EXIT
trap 'cleanup 129' HUP
trap 'cleanup 130' INT
trap 'cleanup 143' TERM

expect_ok() {
    local scenario=$1 label=$2
    shift 2
    "$@" >"$TMPROOT/$scenario.out" 2>&1
    local rc=$?
    if [ "$rc" -eq 0 ]; then
        PASS=$((PASS + 1))
        printf 'PASS %s: %s\n' "$scenario" "$label"
    else
        FAIL=$((FAIL + 1))
        printf 'FAIL %s: %s (exit %s)\n' "$scenario" "$label" "$rc" >&2
        while IFS= read -r line; do printf '  %s\n' "$line" >&2; done <"$TMPROOT/$scenario.out"
    fi
}

expect_fail() {
    local scenario=$1 label=$2 evidence=$3
    shift 3
    "$@" >"$TMPROOT/$scenario.out" 2>&1
    local rc=$?
    if [ "$rc" -ne 0 ] && grep -Fq -- "$evidence" "$TMPROOT/$scenario.out"; then
        PASS=$((PASS + 1))
        printf 'PASS %s: %s\n' "$scenario" "$label"
    else
        FAIL=$((FAIL + 1))
        printf 'FAIL %s: %s (exit %s; expected %s)\n' "$scenario" "$label" "$rc" "$evidence" >&2
        while IFS= read -r line; do printf '  %s\n' "$line" >&2; done <"$TMPROOT/$scenario.out"
    fi
}

make_claim_only_stub() {
    local path=$1
    cat >"$path" <<'STUB'
#!/bin/bash
set -u

repo_root=$(git rev-parse --show-toplevel) || exit 1
git_dir=$(git rev-parse --absolute-git-dir) || exit 1
common_dir=$(git rev-parse --git-common-dir) || exit 1
repo_root=$(realpath "$repo_root") || exit 1
git_dir=$(realpath "$git_dir") || exit 1
common_dir=$(realpath "$common_dir") || exit 1
hooks_path=$(git config --path --get core.hooksPath) || exit 1
if [ "${hooks_path#/}" = "$hooks_path" ]; then hooks_path="$repo_root/$hooks_path"; fi
hooks_path=$(realpath "$hooks_path") || exit 1
head=$(git rev-parse HEAD) || exit 1
tree=$(git write-tree) || exit 1
contract=$(sha256sum "$hooks_path/ipz-remote-php-gate") || exit 1
contract=${contract%% *}
hook=$(sha256sum "$hooks_path/reference-transaction") || exit 1
hook=${hook%% *}
repo=$(sha256sum <<<"$common_dir:$repo_root") || exit 1
repo=${repo%% *}
worktree=$(sha256sum <<<"$git_dir:$repo_root") || exit 1
worktree=${worktree%% *}
nonce=$(printf '%064d' 0)
ref=$(git symbolic-ref -q HEAD) || exit 1
claim="$git_dir/ipz-remote-gate.claim"
umask 077
{
    printf 'version=2\n'
    printf 'head=%s\n' "$head"
    printf 'tree=%s\n' "$tree"
    printf 'parents=%s\n' "$head"
    printf 'contract=%s\n' "$contract"
    printf 'hook=%s\n' "$hook"
    printf 'nonce=%s\n' "$nonce"
    printf 'repo=%s\n' "$repo"
    printf 'worktree=%s\n' "$worktree"
    printf 'created=%s\n' "$(date +%s)"
    printf 'ref_state=symbolic\n'
    printf 'ref=%s\n' "$ref"
} >"$claim" || exit 1
chmod 600 "$claim"
STUB
    chmod 755 "$path"
}

setup_fixture() {
    local origin=$TMPROOT/origin.git work=$TMPROOT/work
    git init --bare -q "$origin" || return 1
    git clone -q "$origin" "$work" || return 1
    git -C "$work" checkout -q -b master || return 1
    git -C "$work" config user.name 'Gate Trust Test'
    git -C "$work" config user.email 'gate-trust@example.invalid'
    mkdir -p "$work/.dev-config/hooks" "$work/.dev-config/bin"
    cp "$SOURCE_ROOT/.dev-config/hooks/pre-commit" "$work/.dev-config/hooks/pre-commit" || return 1
    cp "$SOURCE_ROOT/.dev-config/hooks/reference-transaction" "$work/.dev-config/hooks/reference-transaction" || return 1
    cp "$SOURCE_ROOT/.dev-config/bin/install-ipz-gate" "$work/.dev-config/bin/install-ipz-gate" || return 1
    cp "$SOURCE_ROOT/.dev-config/bin/approve-gate-change" "$work/.dev-config/bin/approve-gate-change" || return 1
    make_claim_only_stub "$work/.dev-config/bin/ipz-remote-php-gate" || return 1
    cat >"$work/.dev-config/bin/lint" <<'LINT'
#!/bin/bash
exit 0
LINT
    chmod 755 "$work/.dev-config/hooks/pre-commit" \
        "$work/.dev-config/hooks/reference-transaction" \
        "$work/.dev-config/bin/install-ipz-gate" \
        "$work/.dev-config/bin/approve-gate-change" \
        "$work/.dev-config/bin/lint" || return 1
    printf 'base\n' >"$work/README.test"
    git -C "$work" add .dev-config README.test || return 1
    git -C "$work" -c core.hooksPath=/dev/null commit -q -m base || return 1
    git -C "$work" push -q origin master || return 1
    git -C "$work" fetch -q origin || return 1
    (cd "$work" && .dev-config/bin/install-ipz-gate) || return 1
}

setup_fixture || {
    printf 'FAIL setup: could not create the gate fixture\n' >&2
    exit 1
}

WORK=$TMPROOT/work
COMMON=$(git -C "$WORK" rev-parse --git-common-dir) || exit 1
COMMON=$(realpath "$WORK/$COMMON" 2>/dev/null || realpath "$COMMON") || exit 1
TOKEN=$COMMON/ipz-gate-owner-token

printf 'normal change\n' >>"$WORK/README.test"
git -C "$WORK" add README.test
expect_ok S1 'normal commit passes through the installed hooks' git -C "$WORK" commit -m 'normal commit'

printf '\n# S2 protected edit\n' >>"$WORK/.dev-config/hooks/pre-commit"
git -C "$WORK" add .dev-config/hooks/pre-commit
expect_fail S2 'gate-source edit is blocked without an owner token' \
    'Gate-source changes require owner approval' git -C "$WORK" commit -m 'unapproved gate edit'

expect_ok S3 'owner token approves the exact staged gate edit' bash -c "cd \"$WORK\" && .dev-config/bin/approve-gate-change --force && git commit -m 'approved gate edit'"
APPROVED_HEAD=$(git -C "$WORK" rev-parse HEAD) || exit 1
if [ ! -e "$TOKEN" ] && [ ! -L "$TOKEN" ]; then
    PASS=$((PASS + 1))
    printf 'PASS S3: successful commit burns the owner token\n'
else
    FAIL=$((FAIL + 1))
    printf 'FAIL S3: successful commit did not burn the owner token\n' >&2
fi
git -C "$WORK" -c core.hooksPath=/dev/null reset --soft HEAD~1 || exit 1
expect_fail S3 'replaying the identical approved gate edit needs a new token' \
    'Gate-source changes require owner approval' git -C "$WORK" commit -m 'approved gate edit'
git -C "$WORK" -c core.hooksPath=/dev/null reset --hard -q "$APPROVED_HEAD" || exit 1

VALID_INSTALL=$(git -C "$WORK" config --worktree --path --get core.hooksPath) || exit 1
LEGACY=$COMMON/ipz-remote-gate-hooks
cp "$VALID_INSTALL/pre-commit" "$LEGACY/pre-commit" || exit 1
cp "$VALID_INSTALL/reference-transaction" "$LEGACY/reference-transaction" || exit 1
cp "$VALID_INSTALL/ipz-remote-php-gate" "$LEGACY/ipz-remote-php-gate" || exit 1
chmod 500 "$LEGACY/pre-commit" "$LEGACY/reference-transaction" "$LEGACY/ipz-remote-php-gate" || exit 1
chmod 700 "$LEGACY" || exit 1
git -C "$WORK" config --worktree core.hooksPath "$LEGACY"
printf 'legacy install\n' >>"$WORK/README.test"
git -C "$WORK" add README.test
expect_ok S4 'trusted legacy flat install remains accepted' \
    git -C "$WORK" commit -m 'legacy flat install'

UNTRUSTED=$COMMON/ipz-remote-gate-hooks/0123456789ab
mkdir -p "$UNTRUSTED" || exit 1
cp "$VALID_INSTALL/pre-commit" "$UNTRUSTED/pre-commit" || exit 1
cp "$VALID_INSTALL/reference-transaction" "$UNTRUSTED/reference-transaction" || exit 1
cp "$VALID_INSTALL/ipz-remote-php-gate" "$UNTRUSTED/ipz-remote-php-gate" || exit 1
chmod u+w "$UNTRUSTED/pre-commit" || exit 1
printf '\n# untrusted sandbox byte\n' >>"$UNTRUSTED/pre-commit"
chmod 500 "$UNTRUSTED" "$UNTRUSTED/pre-commit" "$UNTRUSTED/reference-transaction" "$UNTRUSTED/ipz-remote-php-gate" || exit 1
git -C "$WORK" config --worktree core.hooksPath "$UNTRUSTED"
printf 'untrusted install\n' >>"$WORK/README.test"
git -C "$WORK" add README.test
expect_fail S4 'untrusted versioned install is rejected' 'Trusted IPZ gate installation is missing' \
    git -C "$WORK" commit -m 'untrusted install'
git -C "$WORK" reset -q HEAD README.test
git -C "$WORK" checkout -- README.test
expect_ok S5 'first worktree pins the current trusted gate version' bash -c "cd \"$WORK\" && .dev-config/bin/install-ipz-gate"
FIRST_HOOKS=$(git -C "$WORK" config --worktree --path --get core.hooksPath) || exit 1

printf '\n# S5 newer landed gate version\n' >>"$WORK/.dev-config/hooks/pre-commit"
git -C "$WORK" add .dev-config/hooks/pre-commit || exit 1
git -C "$WORK" -c core.hooksPath=/dev/null commit -q -m 'S5 newer landed gate version' || exit 1
git -C "$WORK" update-ref refs/remotes/origin/master HEAD || exit 1

SECOND=$TMPROOT/second-worktree
git -C "$WORK" worktree add -q -b gate-trust-second "$SECOND" HEAD || exit 1
expect_ok S5 'second worktree installs the newer trusted version pin' bash -c "cd \"$SECOND\" && .dev-config/bin/install-ipz-gate"
SECOND_HOOKS=$(git -C "$SECOND" config --worktree --path --get core.hooksPath) || exit 1
if [ "$FIRST_HOOKS" != "$SECOND_HOOKS" ]; then
    PASS=$((PASS + 1))
    printf 'PASS S5: worktrees pin distinct landed gate versions\n'
else
    FAIL=$((FAIL + 1))
    printf 'FAIL S5: worktrees unexpectedly pin the same gate version\n' >&2
fi
printf 'first worktree change\n' >>"$WORK/README.test"
git -C "$WORK" add README.test
expect_ok S5 'first worktree commits with its old trusted pin' git -C "$WORK" commit -m 'first worktree commit'
printf 'second worktree change\n' >>"$SECOND/README.test"
git -C "$SECOND" add README.test
expect_ok S5 'second worktree commits with its newer pin' git -C "$SECOND" commit -m 'second worktree commit'
printf 'INFO S5: first pin=%s second pin=%s\n' "$FIRST_HOOKS" "$SECOND_HOOKS"

EXISTING_SUITE=$TMPROOT/ipz-remote-php-gate.test.sh
EXISTING_OUT=$TMPROOT/ipz-remote-php-gate.test.out
cp "$SOURCE_ROOT/.dev-config/tests/ipz-remote-php-gate.test.sh" "$EXISTING_SUITE" || exit 1
if bash "$EXISTING_SUITE" >"$EXISTING_OUT" 2>&1; then
    PASS=$((PASS + 1))
    printf 'PASS existing ipz-remote-php-gate regression suite\n'
elif grep -Eiq 'cannot connect to (private )?remote|private remote server.*(unavailable|unreachable)|connection (refused|timed out)|no route to host|network is unreachable|could not resolve host' "$EXISTING_OUT"; then
    existing_error=$(grep -Eim1 'cannot connect to (private )?remote|private remote server.*(unavailable|unreachable)|connection (refused|timed out)|no route to host|network is unreachable|could not resolve host' "$EXISTING_OUT")
    printf 'SKIP existing ipz-remote-php-gate test suite (private remote unavailable): %s\n' "$existing_error"
    FAIL=$((FAIL + 1))
    printf 'FAIL existing ipz-remote-php-gate regression suite (private remote unavailable)\n' >&2
else
    FAIL=$((FAIL + 1))
    printf 'FAIL existing ipz-remote-php-gate regression suite\n' >&2
    while IFS= read -r line; do printf '  %s\n' "$line" >&2; done <"$EXISTING_OUT"
fi

printf 'RESULT: %s passed, %s failed\n' "$PASS" "$FAIL"
[ "$FAIL" -eq 0 ]
