#!/usr/bin/env bash
# Tests for review-gate CLI
# Run: bash skills/review-gate/tests/test-review-gate.sh

set -uo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REVIEW_GATE="$SCRIPT_DIR/../scripts/review-gate"
PASSED=0
FAILED=0

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
NC='\033[0m'

# Test state directory (isolated per test run)
TEST_STATE_DIR=$(mktemp -d)
export REVIEW_STATE_DIR="$TEST_STATE_DIR"

cleanup() {
    rm -rf "$TEST_STATE_DIR"
}
trap cleanup EXIT

# Test helpers
assert_exit_code() {
    local description="$1"
    local expected="$2"
    local actual="$3"

    if [[ "$actual" == "$expected" ]]; then
        echo -e "${GREEN}PASS${NC}: $description"
        ((PASSED++))
    else
        echo -e "${RED}FAIL${NC}: $description"
        echo "  Expected exit code: $expected, Actual: $actual"
        ((FAILED++))
    fi
}

assert_output_contains() {
    local description="$1"
    local pattern="$2"
    local output="$3"

    if echo "$output" | grep -q "$pattern"; then
        echo -e "${GREEN}PASS${NC}: $description"
        ((PASSED++))
    else
        echo -e "${RED}FAIL${NC}: $description"
        echo "  Pattern not found: '$pattern'"
        echo "  Output was:"
        echo "$output" | sed 's/^/    /'
        ((FAILED++))
    fi
}

assert_output_not_contains() {
    local description="$1"
    local pattern="$2"
    local output="$3"

    if ! echo "$output" | grep -q "$pattern"; then
        echo -e "${GREEN}PASS${NC}: $description"
        ((PASSED++))
    else
        echo -e "${RED}FAIL${NC}: $description"
        echo "  Pattern found but should not be: '$pattern'"
        ((FAILED++))
    fi
}

assert_file_exists() {
    local description="$1"
    local file="$2"

    if [[ -f "$file" ]]; then
        echo -e "${GREEN}PASS${NC}: $description"
        ((PASSED++))
    else
        echo -e "${RED}FAIL${NC}: $description"
        echo "  File does not exist: $file"
        ((FAILED++))
    fi
}

assert_file_not_exists() {
    local description="$1"
    local file="$2"

    if [[ ! -f "$file" ]]; then
        echo -e "${GREEN}PASS${NC}: $description"
        ((PASSED++))
    else
        echo -e "${RED}FAIL${NC}: $description"
        echo "  File exists but should not: $file"
        ((FAILED++))
    fi
}

assert_json_field() {
    local description="$1"
    local expected="$2"
    local field="$3"
    local file="$4"

    local actual
    actual=$(jq -r "$field" "$file" 2>/dev/null)

    if [[ "$actual" == "$expected" ]]; then
        echo -e "${GREEN}PASS${NC}: $description"
        ((PASSED++))
    else
        echo -e "${RED}FAIL${NC}: $description"
        echo "  Expected $field: '$expected', Actual: '$actual'"
        ((FAILED++))
    fi
}

run_gate() {
    "$REVIEW_GATE" "$@" 2>&1
}

run_gate_status() {
    "$REVIEW_GATE" "$@" 2>&1
    echo $?
}

echo "=== Review Gate CLI Tests ==="
echo "State dir: $TEST_STATE_DIR"
echo ""

# --- Help Command ---
echo "## Help Command"

output=$(run_gate help)
assert_output_contains "Help shows check command" "check \[session\]" "$output"
assert_output_contains "Help shows enable command" "enable \[session\]" "$output"
assert_output_contains "Help shows approve command" "approve \[session\]" "$output"
assert_output_contains "Help shows reject command" "reject \[session\]" "$output"

# --- Check Without State ---
echo ""
echo "## Check Without State (No Review Required)"

output=$(run_gate check no-state-session)
exit_code=$?
assert_exit_code "Check returns 0 when no state exists" "0" "$exit_code"
assert_output_contains "Check indicates no review required" "No review required" "$output"

# --- Enable Command ---
echo ""
echo "## Enable Command"

output=$(run_gate enable test-enable)
assert_output_contains "Enable confirms session" "Review enabled" "$output"
assert_file_exists "State file created" "$TEST_STATE_DIR/test-enable.json"
assert_json_field "Status is pending" "pending" ".status" "$TEST_STATE_DIR/test-enable.json"
assert_json_field "Session ID stored" "test-enable" ".session_id" "$TEST_STATE_DIR/test-enable.json"

# --- Check When Pending ---
echo ""
echo "## Check When Pending (Should Block)"

run_gate enable test-pending > /dev/null
output=$(run_gate check test-pending)
exit_code=$?
assert_exit_code "Check returns 2 when pending (blocks hook)" "2" "$exit_code"
assert_output_contains "Check outputs decision: block" '"decision": "block"' "$output"
assert_output_contains "Check reason mentions pending" "pending" "$output"

# --- Approve Command ---
echo ""
echo "## Approve Command"

run_gate enable test-approve > /dev/null
output=$(run_gate approve test-approve)
assert_output_contains "Approve confirms" "Review approved" "$output"
assert_json_field "Status changed to approved" "approved" ".status" "$TEST_STATE_DIR/test-approve.json"

# --- Check When Approved ---
echo ""
echo "## Check When Approved (Should Allow)"

output=$(run_gate check test-approve)
exit_code=$?
assert_exit_code "Check returns 0 when approved" "0" "$exit_code"
assert_output_contains "Check shows approved" "approved" "$output"

# --- Reject Command ---
echo ""
echo "## Reject Command"

run_gate enable test-reject > /dev/null
output=$(run_gate reject test-reject "Missing tests")
assert_output_contains "Reject confirms" "Review rejected" "$output"
assert_output_contains "Reject shows reason" "Missing tests" "$output"
assert_json_field "Status changed to rejected" "rejected" ".status" "$TEST_STATE_DIR/test-reject.json"
assert_json_field "Reason stored" "Missing tests" ".reason" "$TEST_STATE_DIR/test-reject.json"

# --- Check When Rejected ---
echo ""
echo "## Check When Rejected (Should Block)"

output=$(run_gate check test-reject)
exit_code=$?
assert_exit_code "Check returns 2 when rejected (blocks hook)" "2" "$exit_code"
assert_output_contains "Check outputs decision: block" '"decision": "block"' "$output"
assert_output_contains "Check reason mentions rejection reason" "Missing tests" "$output"

# --- Reject With Issues ---
echo ""
echo "## Reject With Multiple Issues"

run_gate enable test-issues > /dev/null
output=$(run_gate reject test-issues "Quality issues" "No unit tests" "Missing docs" "Bad naming")

issues=$(jq -r '.issues | length' "$TEST_STATE_DIR/test-issues.json")
if [[ "$issues" == "3" ]]; then
    echo -e "${GREEN}PASS${NC}: Three issues stored"
    ((PASSED++))
else
    echo -e "${RED}FAIL${NC}: Three issues stored (got $issues)"
    ((FAILED++))
fi

assert_json_field "First issue stored" "No unit tests" ".issues[0]" "$TEST_STATE_DIR/test-issues.json"

# Check displays issues
output=$(run_gate check test-issues)
assert_output_contains "Check displays issues" "No unit tests" "$output"

# --- Status Command ---
echo ""
echo "## Status Command"

output=$(run_gate status test-issues)
assert_output_contains "Status shows session" "test-issues" "$output"
assert_output_contains "Status shows rejected" "rejected" "$output"

# Status for non-existent session
output=$(run_gate status nonexistent)
assert_output_contains "Status handles missing session" "No review state" "$output"

# --- List Command ---
echo ""
echo "## List Command"

output=$(run_gate list)
assert_output_contains "List shows test-enable" "test-enable" "$output"
assert_output_contains "List shows test-approve" "test-approve" "$output"
assert_output_contains "List shows statuses" "approved" "$output"
assert_output_contains "List shows rejected" "rejected" "$output"

# --- Session ID Auto-Detection ---
echo ""
echo "## Session ID Auto-Detection"

# From REVIEW_SESSION_ID
export REVIEW_SESSION_ID="env-review-id"
output=$(run_gate enable)
assert_file_exists "Uses REVIEW_SESSION_ID" "$TEST_STATE_DIR/env-review-id.json"
unset REVIEW_SESSION_ID

# From CLAUDE_SESSION_ID
export CLAUDE_SESSION_ID="env-claude-id"
output=$(run_gate enable)
assert_file_exists "Uses CLAUDE_SESSION_ID" "$TEST_STATE_DIR/env-claude-id.json"
unset CLAUDE_SESSION_ID

# --- Approve Without Prior Enable ---
echo ""
echo "## Approve Without Prior Enable"

output=$(run_gate approve new-approve)
assert_output_contains "Approve works without enable" "approved" "$output"
assert_file_exists "State file created on approve" "$TEST_STATE_DIR/new-approve.json"

# --- Re-enable After Approve ---
echo ""
echo "## Re-enable After Approve (Workflow Reset)"

run_gate approve reset-session > /dev/null
run_gate enable reset-session > /dev/null
assert_json_field "Status reset to pending" "pending" ".status" "$TEST_STATE_DIR/reset-session.json"

output=$(run_gate check reset-session)
exit_code=$?
assert_exit_code "Check blocks after re-enable" "2" "$exit_code"

# --- Circuit Breaker ---
echo ""
echo "## Circuit Breaker (Prevents Infinite Loop)"

# Enable a review
run_gate enable test-circuit > /dev/null

# Simulate multiple stop_hook_active=true continuations
# Default MAX_BLOCK_ATTEMPTS is 3
echo '{"stop_hook_active": true}' | run_gate check test-circuit > /dev/null 2>&1 || true  # attempt 1
echo '{"stop_hook_active": true}' | run_gate check test-circuit > /dev/null 2>&1 || true  # attempt 2

# Third attempt should trip circuit breaker
output=$(echo '{"stop_hook_active": true}' | run_gate check test-circuit 2>&1)
exit_code=$?

assert_exit_code "Circuit breaker trips after max attempts" "0" "$exit_code"
assert_output_contains "Circuit breaker message shown" "CIRCUIT BREAKER" "$output"

# Attempts file should be cleaned up
if [[ ! -f "$TEST_STATE_DIR/test-circuit.attempts" ]]; then
    echo -e "${GREEN}PASS${NC}: Attempts file cleaned after circuit breaker"
    ((PASSED++))
else
    echo -e "${RED}FAIL${NC}: Attempts file should be cleaned after circuit breaker"
    ((FAILED++))
fi

# --- Clean Command ---
echo ""
echo "## Clean Command"

# Create an old file (touch with old timestamp not reliable in all envs, so just test the command runs)
output=$(run_gate clean 0d)
assert_output_contains "Clean runs" "Cleaning" "$output"

# --- Unknown Command ---
echo ""
echo "## Error Handling"

output=$(run_gate unknown-cmd 2>&1)
exit_code=$?
assert_exit_code "Unknown command returns 1" "1" "$exit_code"
assert_output_contains "Unknown command shows error" "Unknown command" "$output"

# --- Summary ---
echo ""
echo "=== Summary ==="
echo -e "Passed: ${GREEN}$PASSED${NC}"
echo -e "Failed: ${RED}$FAILED${NC}"

if [[ $FAILED -gt 0 ]]; then
    exit 1
fi

echo ""
echo -e "${GREEN}All tests passed!${NC}"
