#!/usr/bin/env bash
# Regression harness for ci-queue-wait.sh's 404-branch-absent handling.
#
# gitea_get_branch_head_sha() resolves a branch's head SHA before the
# pre-push queue guard runs. A branch that has never been pushed doesn't
# exist on the remote yet, so Gitea's branches/<branch> endpoint 404s.
# Before the fix, `curl -fsSL` failed on the 404, its empty stdout was piped
# into `python3 -c 'json.load(sys.stdin)'`, and the resulting
# JSONDecodeError crashed the guard -- blocking every new feature branch's
# first push. The fix must treat 404 as "no in-flight pipeline" (queue
# clear) while still failing closed on a genuine API error.
#
# Covers:
#   (a) 404 branch-absent          -> exit 0, "queue clear" message.
#   (b) 200 existing branch + a terminal CI state -> unchanged behavior.
#   (c) genuine API error (500)    -> loud, audited CANNOT_ASSERT; degraded exit 0.

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
WORK_DIR="${MOSAIC_TEST_WORK_DIR:-$PWD/.mosaic-test-work/ci-queue-wait-branch-absent}"
REPO_DIR="$WORK_DIR/repo"
STUB_DIR="$WORK_DIR/stubs"

rm -rf "$WORK_DIR"
mkdir -p "$REPO_DIR" "$STUB_DIR"

git -C "$REPO_DIR" init -q
git -C "$REPO_DIR" remote add origin https://git.example.test/acme/widgets.git

# Minimal curl stub. Selects a canned response by inspecting which Gitea
# endpoint is being hit (branches/<branch> vs commits/<sha>/status) and
# whether -w '%{http_code}' was requested. Only the patched branch-lookup
# call passes -w; the unpatched call and the (unchanged) status call both
# use plain `curl -fsSL` semantics -- exit nonzero and print nothing on a
# non-2xx response. This lets the same stub exercise both the pre-fix and
# post-fix branch-lookup code paths faithfully.
cat > "$STUB_DIR/curl" <<'SH'
#!/usr/bin/env bash
set -euo pipefail

has_w=0
url=""
for arg in "$@"; do
    case "$arg" in
        -w) has_w=1 ;;
        http://*|https://*) url="$arg" ;;
    esac
done

case "$url" in
    */branches/*) mode="${MOSAIC_STUB_BRANCH_MODE:?MOSAIC_STUB_BRANCH_MODE not set}" ;;
    */status)     mode="${MOSAIC_STUB_STATUS_MODE:-terminal-success}" ;;
    *)
        echo "curl stub: unrecognized URL: $url" >&2
        exit 2
        ;;
esac

case "$mode" in
    404)  code=404; body="" ;;
    200)  code=200; body='{"commit":{"id":"deadbeefcafef00d0123456789abcdef01234567"}}' ;;
    500)  code=500; body='{"message":"internal server error"}' ;;
    no-status)         code=200; body='{}' ;;
    terminal-success)  code=200; body='{"state":"success","statuses":[{"status":"success"}]}' ;;
    *)
        echo "curl stub: unknown mode=$mode" >&2
        exit 2
        ;;
esac

if [[ "$has_w" == 1 ]]; then
    printf '%s\n%s' "$body" "$code"
    exit 0
fi

# Unpatched branch-lookup call / status-endpoint call: real curl -fsSL
# exits nonzero and emits nothing on stdout for a non-2xx response.
if [[ "$code" != "200" ]]; then
    exit 22
fi
printf '%s' "$body"
SH
chmod +x "$STUB_DIR/curl"

run_ci_queue_wait() {
    local branch="$1"
    (
        cd "$REPO_DIR"
        export PATH="$STUB_DIR:$PATH"
        export MOSAIC_CREDENTIALS_FILE="$WORK_DIR/no-credentials.json"
        export GITEA_TOKEN="stub-token"
        export GITEA_URL="https://git.example.test"
        export MOSAIC_CI_QUEUE_AUDIT_LOG="$WORK_DIR/audit/ci-queue-wait.jsonl"
        "$SCRIPT_DIR/ci-queue-wait.sh" -B "$branch" --purpose push -t 5 -i 1
    )
}

fail=0

# (a) 404 branch-absent -> queue clear, exit 0.
set +e
out_a=$(MOSAIC_STUB_BRANCH_MODE=404 run_ci_queue_wait "feat/not-pushed-yet" 2>&1)
status_a=$?
set -e
if [[ "$status_a" -ne 0 ]]; then
    echo "FAIL(a): expected exit 0 for 404 branch-absent, got $status_a" >&2
    echo "$out_a" >&2
    fail=1
elif [[ "$out_a" != *"queue clear"* ]]; then
    echo "FAIL(a): expected a queue-clear message, got:" >&2
    echo "$out_a" >&2
    fail=1
fi

# (b) 200 existing branch + terminal CI state -> unchanged behavior, exit 0.
set +e
out_b=$(MOSAIC_STUB_BRANCH_MODE=200 MOSAIC_STUB_STATUS_MODE=terminal-success run_ci_queue_wait "main" 2>&1)
status_b=$?
set -e
if [[ "$status_b" -ne 0 ]]; then
    echo "FAIL(b): expected exit 0 for existing branch with terminal status, got $status_b" >&2
    echo "$out_b" >&2
    fail=1
elif [[ "$out_b" != *"sha=deadbeefcafef00d0123456789abcdef01234567"* ]]; then
    echo "FAIL(b): expected the resolved HEAD SHA to be logged, got:" >&2
    echo "$out_b" >&2
    fail=1
elif [[ "$out_b" == *"queue clear"* ]]; then
    echo "FAIL(b): an existing branch must not take the branch-absent path" >&2
    echo "$out_b" >&2
    fail=1
fi

# (c) genuine API error (500) -> CANNOT_ASSERT is loud and audited, but does not brick delivery.
set +e
out_c=$(MOSAIC_STUB_BRANCH_MODE=500 run_ci_queue_wait "feat/some-branch" 2>&1)
status_c=$?
set -e
if [[ "$status_c" -ne 0 ]]; then
    echo "FAIL(c): expected degraded exit 0 for provider unavailability, got $status_c" >&2
    echo "$out_c" >&2
    fail=1
elif [[ "$out_c" != *"CANNOT_ASSERT"* ]]; then
    echo "FAIL(c): expected a loud CANNOT_ASSERT diagnostic" >&2
    echo "$out_c" >&2
    fail=1
elif [[ "$out_c" == *"queue clear"* ]]; then
    echo "FAIL(c): a genuine API error must not be reported as queue-clear" >&2
    echo "$out_c" >&2
    fail=1
elif [[ ! -s "$WORK_DIR/audit/ci-queue-wait.jsonl" ]]; then
    echo "FAIL(c): expected a durable CANNOT_ASSERT audit record" >&2
    fail=1
fi

if [[ "$fail" -eq 0 ]]; then
    echo "ci-queue-wait branch-absent regression passed (3/3 cases)"
fi

exit "$fail"
