#!/bin/bash
# Hermetic regression coverage for Gitea PR diff construction and fail-closed reviews.
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
TMP_DIR=$(mktemp -d)
trap 'rm -rf "$TMP_DIR"' EXIT

fail() {
    echo "not ok - $*" >&2
    exit 1
}

assert_contains() {
    local haystack="$1" needle="$2"
    if [[ "$haystack" != *"$needle"* ]]; then
        printf 'actual output:\n%s\n' "$haystack" >&2
        fail "expected output to contain: $needle"
    fi
}

# Prevent CI-provided repository context from leaking into the fixture repositories.
unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE GIT_OBJECT_DIRECTORY \
    GIT_ALTERNATE_OBJECT_DIRECTORIES GIT_COMMON_DIR
export GIT_AUTHOR_NAME="Codex Fixture"
export GIT_AUTHOR_EMAIL="codex-fixture@example.test"
export GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME"
export GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL"
export GITEA_LOGIN="fixture"
export GITEA_TOKEN="fixture-token"
export GITEA_URL="file://$TMP_DIR"

create_pr_fixture() {
    local fixture_root="$1" head_mode="$2"
    local origin="$fixture_root/origin.git"
    local seed="$fixture_root/seed"
    local work="$fixture_root/work"
    local base_sha head_sha

    mkdir -p "$fixture_root"
    git init --quiet --bare "$origin"
    git init --quiet --initial-branch=release/next "$seed"
    printf 'base\n' > "$seed/pr-change.ts"
    git -C "$seed" add pr-change.ts
    git -C "$seed" commit --quiet -m "fixture base"
    base_sha=$(git -C "$seed" rev-parse HEAD)
    git -C "$seed" remote add origin "$origin"
    git -C "$seed" push --quiet origin release/next
    git --git-dir="$origin" symbolic-ref HEAD refs/heads/release/next

    if [[ "$head_mode" == "changed" ]]; then
        git -C "$seed" switch --quiet -c feature/pr-795
        printf 'actual-pr-change\n' > "$seed/pr-change.ts"
        git -C "$seed" commit --quiet -am "fixture PR head"
        head_sha=$(git -C "$seed" rev-parse HEAD)
        git -C "$seed" push --quiet origin HEAD:refs/pull/795/head
    else
        head_sha="$base_sha"
        git --git-dir="$origin" update-ref refs/pull/795/head "$head_sha"
    fi

    # Gitea's provider-owned PR head ref now exists in the local bare origin.
    git clone --quiet "$origin" "$work"
    printf '%s\n' "$work"
}

FAKE_BIN="$TMP_DIR/bin"
mkdir -p "$FAKE_BIN"
cat > "$FAKE_BIN/tea" <<'STUB'
#!/bin/bash
if [[ "$*" == "pr list --fields index,base --output simple" ]]; then
    printf '795 release/next\n'
    exit 0
fi
exit 1
STUB
cat > "$FAKE_BIN/codex" <<'STUB'
#!/bin/bash
printf 'CODEX %s\n' "$*" >> "$CODEX_LOG"
exit 99
STUB
chmod +x "$FAKE_BIN/tea" "$FAKE_BIN/codex"
export PATH="$FAKE_BIN:$PATH"

# The valid fixture is a fresh clone on the non-main base. The PR head exists only
# at refs/pull/795/head, so local HEAD cannot accidentally satisfy the assertion.
if [[ "${1:-all}" != "fail-closed" ]]; then
    VALID_WORK=$(create_pr_fixture "$TMP_DIR/valid" changed)
    (
        cd "$VALID_WORK"
        # shellcheck source=common.sh
        source "$SCRIPT_DIR/common.sh"
        diff_context=$(build_diff_context pr 795)
        assert_contains "$diff_context" "actual-pr-change"

        base_sha=$(git rev-parse refs/remotes/origin/release/next)
        head_sha=$(git rev-parse refs/remotes/origin/pr/795/head)
        local_sha=$(git rev-parse HEAD)
        [[ "$local_sha" == "$base_sha" ]] || fail "fixture clone is not on the PR base"
        [[ "$head_sha" != "$base_sha" ]] || fail "fixture PR head does not differ from its base"
        git show-ref --verify --quiet refs/remotes/origin/pr/795/head || \
            fail "fetched PR head ref is missing"
        [[ "$(git diff --name-only "${base_sha}...${head_sha}")" == "pr-change.ts" ]] || \
            fail "explicit PR refs do not contain the fixture change"
        if git show-ref --verify --quiet refs/heads/main || \
            git show-ref --verify --quiet refs/remotes/origin/main; then
            fail "fixture unexpectedly contains a main ref"
        fi
    )
    echo "ok - Gitea PR mode fetches and diffs explicit non-main base and PR head refs"
fi

# Build an empty PR entirely inside another local repository. Both review wrappers
# must emit the PR-numbered error before Codex or the stubbed post path can execute.
if [[ "${1:-all}" != "pr-head" ]]; then
    EMPTY_WORK=$(create_pr_fixture "$TMP_DIR/empty" empty)
    SANDBOX="$TMP_DIR/sandbox"
    mkdir -p "$SANDBOX/tools/codex/schemas" "$SANDBOX/tools/git"
    cp "$SCRIPT_DIR/common.sh" \
        "$SCRIPT_DIR/codex-code-review.sh" \
        "$SCRIPT_DIR/codex-security-review.sh" \
        "$SANDBOX/tools/codex/"
    cp "$SCRIPT_DIR/schemas/code-review-schema.json" \
        "$SCRIPT_DIR/schemas/security-review-schema.json" \
        "$SANDBOX/tools/codex/schemas/"
    cp "$SCRIPT_DIR/../git/detect-platform.sh" "$SANDBOX/tools/git/"

    cat > "$SANDBOX/tools/git/pr-review.sh" <<'STUB'
#!/bin/bash
printf 'POST %s\n' "$*" >> "$POST_LOG"
STUB
    chmod +x "$SANDBOX/tools/git/pr-review.sh"

    POST_LOG="$TMP_DIR/post.log"
    CODEX_LOG="$TMP_DIR/codex.log"
    export POST_LOG CODEX_LOG

    for review_kind in code security; do
        : > "$POST_LOG"
        : > "$CODEX_LOG"
        review_script="$SANDBOX/tools/codex/codex-${review_kind}-review.sh"
        set +e
        (
            cd "$EMPTY_WORK"
            "$review_script" -n 795
        ) >"$TMP_DIR/${review_kind}.stdout" 2>"$TMP_DIR/${review_kind}.stderr"
        review_status=$?
        set -e

        stderr_text=$(cat "$TMP_DIR/${review_kind}.stderr")
        [[ "$review_status" -ne 0 ]] || fail "${review_kind} review returned success for an empty PR diff"
        [[ ! -s "$CODEX_LOG" ]] || fail "Codex ran for an empty ${review_kind} PR diff"
        [[ ! -s "$POST_LOG" ]] || fail "${review_kind} review auto-post ran for an empty PR diff"
        assert_contains "$stderr_text" "Error:"
        assert_contains "$stderr_text" "PR #795"
        echo "ok - empty ${review_kind} PR diff fails closed before Codex and auto-post"
    done
fi
