#!/bin/bash
# ci-queue-wait.sh - Wait until project CI queue is clear (no running/queued pipeline on branch head)
# Usage: ci-queue-wait.sh [-B branch] [-t timeout_sec] [-i interval_sec] [--purpose push|merge] [--require-status]

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/detect-platform.sh"

BRANCH="main"
TIMEOUT_SEC=900
INTERVAL_SEC=15
PURPOSE="merge"
REQUIRE_STATUS=0

usage() {
    cat <<EOF
Usage: $(basename "$0") [-B branch] [-t timeout_sec] [-i interval_sec] [--purpose push|merge] [--require-status]

Options:
  -B, --branch BRANCH      Branch head to inspect (default: main)
  -t, --timeout SECONDS    Max wait time in seconds (default: 900)
  -i, --interval SECONDS   Poll interval in seconds (default: 15)
      --purpose VALUE      Log context: push|merge (default: merge)
      --require-status     Fail if no CI status contexts are present
  -h, --help               Show this help

Examples:
  $(basename "$0")
  $(basename "$0") --purpose push -B main -t 600 -i 10
EOF
}

# get_remote_host and get_gitea_token are provided by detect-platform.sh

get_state_from_status_json() {
    python3 - <<'PY'
import json
import sys

try:
    payload = json.load(sys.stdin)
except Exception:
    print("unknown")
    raise SystemExit(0)

statuses = payload.get("statuses") or []
state = (payload.get("state") or "").lower()

pending_values = {"pending", "queued", "running", "waiting"}
failure_values = {"failure", "error", "failed"}
success_values = {"success"}

if state in pending_values:
    print("pending")
    raise SystemExit(0)
if state in failure_values:
    print("terminal-failure")
    raise SystemExit(0)
if state in success_values:
    print("terminal-success")
    raise SystemExit(0)

values = []
for item in statuses:
    if not isinstance(item, dict):
        continue
    value = (item.get("status") or item.get("state") or "").lower()
    if value:
        values.append(value)

if not values and not state:
    print("no-status")
elif any(v in pending_values for v in values):
    print("pending")
elif any(v in failure_values for v in values):
    print("terminal-failure")
elif values and all(v in success_values for v in values):
    print("terminal-success")
else:
    print("unknown")
PY
}

print_pending_contexts() {
    python3 - <<'PY'
import json
import sys

try:
    payload = json.load(sys.stdin)
except Exception:
    print("[ci-queue-wait] unable to decode status payload")
    raise SystemExit(0)

statuses = payload.get("statuses") or []
if not statuses:
    print("[ci-queue-wait] no status contexts reported")
    raise SystemExit(0)

pending_values = {"pending", "queued", "running", "waiting"}
found = False
for item in statuses:
    if not isinstance(item, dict):
        continue
    name = item.get("context") or item.get("name") or "unknown-context"
    value = (item.get("status") or item.get("state") or "unknown").lower()
    target = item.get("target_url") or item.get("url") or ""
    if value in pending_values:
        found = True
        if target:
            print(f"[ci-queue-wait] pending: {name}={value} ({target})")
        else:
            print(f"[ci-queue-wait] pending: {name}={value}")
if not found:
    print("[ci-queue-wait] no pending contexts")
PY
}

github_get_branch_head_sha() {
    local owner="$1"
    local repo="$2"
    local branch="$3"
    gh api "repos/${owner}/${repo}/branches/${branch}" --jq '.commit.sha'
}

github_get_commit_status_json() {
    local owner="$1"
    local repo="$2"
    local sha="$3"
    gh api "repos/${owner}/${repo}/commits/${sha}/status"
}

gitea_get_branch_head_sha() {
    local host="$1"
    local repo="$2"
    local branch="$3"
    local token="$4"
    local url="https://${host}/api/v1/repos/${repo}/branches/${branch}"
    curl -fsSL -H "User-Agent: curl/8" -H "Authorization: token ${token}" "$url" | python3 -c '
import json, sys
data = json.load(sys.stdin)
commit = data.get("commit") or {}
print((commit.get("id") or "").strip())
'
}

gitea_get_commit_status_json() {
    local host="$1"
    local repo="$2"
    local sha="$3"
    local token="$4"
    local url="https://${host}/api/v1/repos/${repo}/commits/${sha}/status"
    curl -fsSL -H "User-Agent: curl/8" -H "Authorization: token ${token}" "$url"
}

while [[ $# -gt 0 ]]; do
    case "$1" in
        -B|--branch)
            BRANCH="$2"
            shift 2
            ;;
        -t|--timeout)
            TIMEOUT_SEC="$2"
            shift 2
            ;;
        -i|--interval)
            INTERVAL_SEC="$2"
            shift 2
            ;;
        --purpose)
            PURPOSE="$2"
            shift 2
            ;;
        --require-status)
            REQUIRE_STATUS=1
            shift
            ;;
        -h|--help)
            usage
            exit 0
            ;;
        *)
            echo "Unknown option: $1" >&2
            usage >&2
            exit 1
            ;;
    esac
done

if ! [[ "$TIMEOUT_SEC" =~ ^[0-9]+$ ]] || ! [[ "$INTERVAL_SEC" =~ ^[0-9]+$ ]]; then
    echo "Error: timeout and interval must be integer seconds." >&2
    exit 1
fi

OWNER=$(get_repo_owner)
REPO=$(get_repo_name)
detect_platform > /dev/null
PLATFORM="${PLATFORM:-unknown}"

if [[ "$PLATFORM" == "github" ]]; then
    if ! command -v gh >/dev/null 2>&1; then
        echo "Error: gh CLI is required for GitHub CI queue guard." >&2
        exit 1
    fi
    HEAD_SHA=$(github_get_branch_head_sha "$OWNER" "$REPO" "$BRANCH")
    if [[ -z "$HEAD_SHA" ]]; then
        echo "Error: Could not resolve ${BRANCH} head SHA." >&2
        exit 1
    fi
    echo "[ci-queue-wait] platform=github purpose=${PURPOSE} branch=${BRANCH} sha=${HEAD_SHA}"
elif [[ "$PLATFORM" == "gitea" ]]; then
    HOST=$(get_remote_host) || {
        echo "Error: Could not determine remote host." >&2
        exit 1
    }
    TOKEN=$(get_gitea_token "$HOST") || {
        echo "Error: Gitea token not found. Set GITEA_TOKEN or configure ~/.git-credentials." >&2
        exit 1
    }
    HEAD_SHA=$(gitea_get_branch_head_sha "$HOST" "$OWNER/$REPO" "$BRANCH" "$TOKEN")
    if [[ -z "$HEAD_SHA" ]]; then
        echo "Error: Could not resolve ${BRANCH} head SHA." >&2
        exit 1
    fi
    echo "[ci-queue-wait] platform=gitea purpose=${PURPOSE} branch=${BRANCH} sha=${HEAD_SHA}"
else
    echo "Error: Unsupported platform '${PLATFORM}'." >&2
    exit 1
fi

START_TS=$(date +%s)
DEADLINE_TS=$((START_TS + TIMEOUT_SEC))

while true; do
    NOW_TS=$(date +%s)
    if (( NOW_TS > DEADLINE_TS )); then
        echo "Error: Timed out waiting for CI queue to clear on ${BRANCH} after ${TIMEOUT_SEC}s." >&2
        exit 124
    fi

    if [[ "$PLATFORM" == "github" ]]; then
        STATUS_JSON=$(github_get_commit_status_json "$OWNER" "$REPO" "$HEAD_SHA")
    else
        STATUS_JSON=$(gitea_get_commit_status_json "$HOST" "$OWNER/$REPO" "$HEAD_SHA" "$TOKEN")
    fi

    STATE=$(printf '%s' "$STATUS_JSON" | get_state_from_status_json)
    echo "[ci-queue-wait] state=${STATE} purpose=${PURPOSE} branch=${BRANCH}"

    case "$STATE" in
        pending)
            printf '%s' "$STATUS_JSON" | print_pending_contexts
            sleep "$INTERVAL_SEC"
            ;;
        no-status)
            if [[ "$REQUIRE_STATUS" -eq 1 ]]; then
                echo "Error: No CI status contexts found for ${BRANCH} while --require-status is set." >&2
                exit 1
            fi
            echo "[ci-queue-wait] no status contexts present; proceeding."
            exit 0
            ;;
        terminal-success|terminal-failure|unknown)
            # Queue guard only blocks on pending/running/queued states.
            exit 0
            ;;
        *)
            echo "[ci-queue-wait] unrecognized state '${STATE}', proceeding conservatively."
            exit 0
            ;;
    esac
done
