#!/usr/bin/env bash
# review-gate - Quality gate CLI for cross-agent review enforcement
#
# Usage:
#   review-gate check [session_id]    - Check if review is approved (for hooks)
#   review-gate enable [session_id]   - Enable review requirement
#   review-gate approve [session_id]  - Mark review as approved
#   review-gate reject [session_id] [reason]  - Mark review as rejected
#   review-gate status [session_id]   - Show current review status
#
# Exit codes:
#   0 - Review approved or not required (allow exit)
#   1 - Review pending or rejected (block exit)

set -euo pipefail

# Session ID: use provided, or env var, or generate from git
get_session_id() {
    local provided="${1:-}"
    if [[ -n "$provided" ]]; then
        echo "$provided"
    elif [[ -n "${REVIEW_SESSION_ID:-}" ]]; then
        echo "$REVIEW_SESSION_ID"
    elif [[ -n "${CLAUDE_SESSION_ID:-}" ]]; then
        echo "$CLAUDE_SESSION_ID"
    else
        # Generate from git state
        local branch=$(git branch --show-current 2>/dev/null || echo "main")
        local short_sha=$(git rev-parse --short HEAD 2>/dev/null || echo "unknown")
        echo "review-${branch}-${short_sha}"
    fi
}

# State file location (simple file-based for prototype)
STATE_DIR="${REVIEW_STATE_DIR:-${PWD}/.review-state}"
mkdir -p "$STATE_DIR"

get_state_file() {
    local session_id="$1"
    echo "${STATE_DIR}/${session_id}.json"
}

# Circuit breaker settings
MAX_BLOCK_ATTEMPTS="${REVIEW_MAX_ATTEMPTS:-3}"

# Commands
cmd_check() {
    local session_id=$(get_session_id "${1:-}")
    local state_file=$(get_state_file "$session_id")
    local attempts_file="${STATE_DIR}/${session_id}.attempts"

    # Check for stop_hook_active (continuation after previous block)
    local hook_input=""
    local stop_hook_active="false"
    if [[ ! -t 0 ]]; then
        hook_input=$(cat 2>/dev/null || true)
    fi

    if [[ -n "$hook_input" ]]; then
        stop_hook_active=$(echo "$hook_input" | jq -r '.stop_hook_active // false' 2>/dev/null || echo "false")
    fi

    # Track block attempts for circuit breaker
    local attempts=0
    if [[ -f "$attempts_file" ]]; then
        attempts=$(cat "$attempts_file" 2>/dev/null || echo "0")
    fi

    # Circuit breaker: if we've hit max attempts, allow exit
    if [[ "$stop_hook_active" == "true" ]]; then
        attempts=$((attempts + 1))
        echo "$attempts" > "$attempts_file"

        if [[ $attempts -ge $MAX_BLOCK_ATTEMPTS ]]; then
            # Circuit breaker tripped
            echo "⚠ CIRCUIT BREAKER: Max block attempts ($MAX_BLOCK_ATTEMPTS) reached"
            echo "Review was not completed. Allowing exit to prevent infinite loop."
            echo "Session: $session_id"
            # Reset attempts for next time
            rm -f "$attempts_file"
            exit 0
        fi
    fi

    if [[ ! -f "$state_file" ]]; then
        # No review registered - allow exit
        echo "No review required for session: $session_id"
        exit 0
    fi

    local status=$(jq -r '.status' "$state_file" 2>/dev/null || echo "unknown")

    case "$status" in
        approved)
            echo "✓ Review approved for session: $session_id"
            exit 0
            ;;
        pending)
            # Exit 2 + JSON to stderr = block in Claude Code Stop hook
            local reason="Review pending for session: $session_id. Spawn a reviewer agent with: /task Review the work. Check git diff and file changes. Then run: review-gate approve $session_id"
            jq -n --arg reason "$reason" '{
                "decision": "block",
                "reason": $reason
            }' >&2
            exit 2
            ;;
        rejected)
            local reject_reason=$(jq -r '.reason // "No reason provided"' "$state_file")
            local issues=$(jq -r '.issues | join(", ")' "$state_file" 2>/dev/null || echo "")
            # Exit 2 + JSON to stderr = block in Claude Code Stop hook
            local reason="Review rejected for session: $session_id. Reason: $reject_reason. Issues: $issues. Fix the issues and request re-review."
            jq -n --arg reason "$reason" '{
                "decision": "block",
                "reason": $reason
            }' >&2
            exit 2
            ;;
        *)
            echo "⚠ Unknown review status: $status"
            exit 1
            ;;
    esac
}

cmd_enable() {
    local session_id=$(get_session_id "${1:-}")
    local state_file=$(get_state_file "$session_id")

    cat > "$state_file" <<EOF
{
    "session_id": "$session_id",
    "status": "pending",
    "enabled_at": "$(date -Iseconds)",
    "enabled_by": "${USER:-unknown}",
    "worker_agent": "${CLAUDE_MODEL:-unknown}",
    "issues": []
}
EOF

    echo "✓ Review enabled for session: $session_id"
    echo "  State file: $state_file"
}

cmd_approve() {
    local session_id=$(get_session_id "${1:-}")
    local state_file=$(get_state_file "$session_id")
    local attempts_file="${STATE_DIR}/${session_id}.attempts"

    if [[ ! -f "$state_file" ]]; then
        echo "No review state for session: $session_id"
        echo "Creating approved state..."
    fi

    cat > "$state_file" <<EOF
{
    "session_id": "$session_id",
    "status": "approved",
    "approved_at": "$(date -Iseconds)",
    "approved_by": "${USER:-unknown}",
    "reviewer_agent": "${CLAUDE_MODEL:-unknown}"
}
EOF

    # Clear circuit breaker attempts
    rm -f "$attempts_file"

    echo "✓ Review approved for session: $session_id"
}

cmd_reject() {
    local session_id=$(get_session_id "${1:-}")
    local reason="${2:-Review failed}"
    local state_file=$(get_state_file "$session_id")

    # Collect any additional args as issues
    shift 2 2>/dev/null || true
    local issues=("$@")

    local issues_json="[]"
    if [[ ${#issues[@]} -gt 0 ]]; then
        issues_json=$(printf '%s\n' "${issues[@]}" | jq -R . | jq -s .)
    fi

    cat > "$state_file" <<EOF
{
    "session_id": "$session_id",
    "status": "rejected",
    "rejected_at": "$(date -Iseconds)",
    "rejected_by": "${USER:-unknown}",
    "reviewer_agent": "${CLAUDE_MODEL:-unknown}",
    "reason": "$reason",
    "issues": $issues_json
}
EOF

    echo "❌ Review rejected for session: $session_id"
    echo "Reason: $reason"
}

cmd_status() {
    local session_id=$(get_session_id "${1:-}")
    local state_file=$(get_state_file "$session_id")

    if [[ ! -f "$state_file" ]]; then
        echo "No review state for session: $session_id"
        exit 0
    fi

    echo "Review state for session: $session_id"
    echo "---"
    jq . "$state_file"
}

cmd_list() {
    echo "Active review sessions:"
    echo "---"
    shopt -s nullglob
    for f in "$STATE_DIR"/*.json; do
        local session=$(basename "$f" .json)
        local status=$(jq -r '.status' "$f" 2>/dev/null || echo "unknown")
        printf "  %-40s %s\n" "$session" "$status"
    done
    shopt -u nullglob
}

cmd_clean() {
    local max_age="${1:-7d}"
    echo "Cleaning review states older than $max_age..."
    find "$STATE_DIR" -name "*.json" -mtime +${max_age%d} -delete 2>/dev/null || true
    echo "Done."
}

# Main
case "${1:-help}" in
    check)
        cmd_check "${2:-}"
        ;;
    enable)
        cmd_enable "${2:-}"
        ;;
    approve)
        cmd_approve "${2:-}"
        ;;
    reject)
        cmd_reject "${2:-}" "${3:-}" "${@:4}"
        ;;
    status)
        cmd_status "${2:-}"
        ;;
    list)
        cmd_list
        ;;
    clean)
        cmd_clean "${2:-7d}"
        ;;
    help|--help|-h)
        echo "review-gate - Quality gate CLI for cross-agent review"
        echo ""
        echo "Commands:"
        echo "  check [session]     Check if review approved (exit 0) or blocked (exit 1)"
        echo "  enable [session]    Enable review requirement for session"
        echo "  approve [session]   Mark review as approved"
        echo "  reject [session] [reason] [issues...]  Mark as rejected"
        echo "  status [session]    Show review status"
        echo "  list                List all review sessions"
        echo "  clean [age]         Clean old review states (default: 7d)"
        echo ""
        echo "Session ID is auto-detected from REVIEW_SESSION_ID, CLAUDE_SESSION_ID,"
        echo "or generated from git branch/commit."
        ;;
    *)
        echo "Unknown command: $1"
        echo "Run 'review-gate help' for usage."
        exit 1
        ;;
esac
