#!/usr/bin/env bash
# scripts/validate_system.sh
#
# End-to-end validation of proxym tool execution pipeline.
# Tests on real projects from /home/tom/github/wronai/*
#
# What it validates:
#   1. API health & connectivity
#   2. Tool registry (all tools registered + adapters)
#   3. Executor auto-start (queue.running == true)
#   4. Ticket lifecycle: create → dispatch → queue → execute → done
#   5. Logs presence after execution
#   6. Multi-project dispatch across real repos
#
# Usage:
#   ./scripts/validate_system.sh                    # default: localhost:4001
#   PROXYM_URL=http://localhost:4000 ./scripts/validate_system.sh
#   ./scripts/validate_system.sh --tool claude-code  # test specific tool
#   ./scripts/validate_system.sh --quick             # health + executor only

set -euo pipefail

# ── Config ────────────────────────────────────────────────
PROXYM_URL="${PROXYM_URL:-http://localhost:4001}"
API_KEY="${PROXYM_API_KEY:-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}"
PROJECTS_ROOT="${PROJECTS_ROOT:-/home/tom/github/wronai}"
TOOL_FILTER="${1:-}"
POLL_INTERVAL=2
POLL_TIMEOUT=60

# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m'

PASS=0
FAIL=0
WARN=0

# ── Helpers ───────────────────────────────────────────────

log_header() { echo -e "\n${CYAN}═══════════════════════════════════════════════════${NC}"; echo -e "${CYAN}  $1${NC}"; echo -e "${CYAN}═══════════════════════════════════════════════════${NC}"; }
log_test()   { echo -e "  ${BLUE}▶${NC} $1"; }
log_pass()   { echo -e "  ${GREEN}✅ PASS${NC}: $1"; PASS=$((PASS+1)); }
log_fail()   { echo -e "  ${RED}❌ FAIL${NC}: $1"; FAIL=$((FAIL+1)); }
log_warn()   { echo -e "  ${YELLOW}⚠️  WARN${NC}: $1"; WARN=$((WARN+1)); }
log_info()   { echo -e "  ${YELLOW}ℹ${NC}  $1"; }

api() {
    # api METHOD PATH [DATA]
    local method="$1" path="$2" data="${3:-}"
    local url="${PROXYM_URL}${path}"
    local args=(-s -w "\n%{http_code}" -H "Authorization: Bearer ${API_KEY}" -H "Content-Type: application/json")
    if [ -n "$data" ]; then
        args+=(-X "$method" -d "$data")
    else
        args+=(-X "$method")
    fi
    curl "${args[@]}" "$url" 2>/dev/null
}

api_get()  { api GET  "$1"; }
api_post() { api POST "$1" "${2:-}"; }

parse_response() {
    # Split response body and HTTP status code
    local response="$1"
    BODY=$(echo "$response" | head -n -1)
    HTTP_CODE=$(echo "$response" | tail -n 1)
}

jq_field() { echo "$BODY" | jq -r "$1" 2>/dev/null; }

# ── Phase 1: Health & Connectivity ────────────────────────

phase_health() {
    log_header "Phase 1: Health & Connectivity"

    log_test "Checking API health at ${PROXYM_URL}"
    parse_response "$(api_get /health)"
    if [ "$HTTP_CODE" = "200" ]; then
        log_pass "API healthy (HTTP 200)"
    else
        log_fail "API unreachable (HTTP ${HTTP_CODE})"
        echo -e "  ${RED}Cannot continue — is proxym running?${NC}"
        echo -e "  Try: docker compose --profile dev up -d"
        exit 1
    fi

    log_test "Checking /v1/models"
    parse_response "$(api_get /v1/models)"
    if [ "$HTTP_CODE" = "200" ]; then
        MODEL_COUNT=$(jq_field '.data | length')
        log_pass "Models endpoint OK (${MODEL_COUNT} models)"
    else
        log_warn "Models endpoint returned HTTP ${HTTP_CODE}"
    fi

    log_test "Checking /v1/budget"
    parse_response "$(api_get /v1/budget)"
    if [ "$HTTP_CODE" = "200" ]; then
        log_pass "Budget endpoint OK"
    else
        log_warn "Budget endpoint returned HTTP ${HTTP_CODE}"
    fi
}

# ── Phase 2: Tool Registry ────────────────────────────────

phase_tools() {
    log_header "Phase 2: Tool Registry"

    log_test "Listing registered tools"
    parse_response "$(api_get /dashboard/tools/)"
    if [ "$HTTP_CODE" != "200" ]; then
        log_fail "Tool list endpoint failed (HTTP ${HTTP_CODE})"
        return
    fi

    TOOL_COUNT=$(jq_field '.count')
    log_pass "Tool registry loaded (${TOOL_COUNT} tools)"

    # Check each tool
    local tools
    tools=$(echo "$BODY" | jq -r '.tools[].name' 2>/dev/null)
    for tool in $tools; do
        local available
        available=$(echo "$BODY" | jq -r ".tools[] | select(.name==\"$tool\") | .available" 2>/dev/null)
        if [ "$available" = "true" ]; then
            log_pass "Tool '${tool}' registered + available"
        else
            log_warn "Tool '${tool}' registered but no available host or docker-backed instance"
        fi
    done

    # Verify all builtin tools have adapters (check via dispatch dry-run)
    local expected_tools="aider claude-code vscode roo-code cline windsurf cursor browser"
    for t in $expected_tools; do
        if echo "$tools" | grep -q "^${t}$"; then
            log_pass "Built-in tool '${t}' in registry"
        else
            log_fail "Built-in tool '${t}' missing from registry"
        fi
    done
}

# ── Phase 3: Executor Status ─────────────────────────────

phase_executor() {
    log_header "Phase 3: Tool Executor"

    log_test "Checking executor status"
    parse_response "$(api_get /dashboard/tools/queue)"
    if [ "$HTTP_CODE" != "200" ]; then
        log_fail "Queue endpoint failed (HTTP ${HTTP_CODE})"
        return
    fi

    local running
    running=$(jq_field '.running')
    if [ "$running" = "true" ]; then
        log_pass "Executor is running (auto-started with app)"
    else
        log_fail "Executor NOT running — jobs will stay queued forever"
        log_info "Attempting to start executor..."
        parse_response "$(api_post /dashboard/tools/queue/start)"
        if [ "$HTTP_CODE" = "200" ]; then
            log_pass "Executor started manually"
        else
            log_fail "Could not start executor (HTTP ${HTTP_CODE})"
        fi
    fi

    local queue_size total_jobs
    queue_size=$(jq_field '.queue_size')
    total_jobs=$(jq_field '.total_jobs')
    log_info "Queue size: ${queue_size}, Total jobs: ${total_jobs}"
}

# ── Phase 4: Ticket Lifecycle ─────────────────────────────

dispatch_and_monitor() {
    # dispatch_and_monitor TOOL PROJECT_DIR TASK_DESCRIPTION
    local tool="$1" project_dir="$2" task="$3"
    local project_name
    project_name=$(basename "$project_dir")

    log_test "Creating ticket for project '${project_name}' with tool '${tool}'"

    # Create ticket with auto-dispatch
    local create_data
    create_data=$(jq -n \
        --arg task "$task" \
        --arg tool "$tool" \
        --arg desc "Validation test: ${tool} on ${project_name}" \
        '{task: $task, tool: $tool, description: $desc, type: "task", priority: "low", tags: ["validation", "auto-test"]}')

    parse_response "$(api_post /dashboard/tickets "$create_data")"
    if [ "$HTTP_CODE" != "200" ]; then
        log_fail "Create ticket failed (HTTP ${HTTP_CODE}): $(echo "$BODY" | head -c 200)"
        return 1
    fi

    local ticket_id
    ticket_id=$(jq_field '.id')
    local job_id
    job_id=$(jq_field '.last_job.job_id')
    local job_status
    job_status=$(jq_field '.last_job.status')

    log_pass "Ticket created: ${ticket_id}"
    log_info "Job: ${job_id} (initial status: ${job_status})"

    # Poll for job completion
    log_test "Monitoring job ${job_id} (timeout: ${POLL_TIMEOUT}s)"
    local elapsed=0
    local final_status="unknown"

    while [ $elapsed -lt $POLL_TIMEOUT ]; do
        sleep $POLL_INTERVAL
        elapsed=$((elapsed + POLL_INTERVAL))

        parse_response "$(api_get "/dashboard/tickets/${ticket_id}")"
        if [ "$HTTP_CODE" != "200" ]; then
            log_warn "Ticket poll failed (HTTP ${HTTP_CODE})"
            continue
        fi

        final_status=$(jq_field '.last_job.status')
        local duration
        duration=$(jq_field '.last_job.duration_s')

        case "$final_status" in
            done)
                log_pass "Job DONE in ${duration}s (ticket: ${ticket_id})"
                # Check stdout_tail for output
                local stdout_tail
                stdout_tail=$(jq_field '.last_job.stdout_tail')
                if [ -n "$stdout_tail" ] && [ "$stdout_tail" != "null" ] && [ "$stdout_tail" != "" ]; then
                    log_pass "Execution logs present (${#stdout_tail} chars)"
                    log_info "Output tail: $(echo "$stdout_tail" | head -c 120)..."
                else
                    log_warn "No stdout captured in execution logs"
                fi
                return 0
                ;;
            failed)
                local error
                error=$(jq_field '.last_job.error')
                log_fail "Job FAILED after ${duration}s: ${error}"
                return 1
                ;;
            running)
                echo -ne "\r    ⏳ Running... (${elapsed}s/${POLL_TIMEOUT}s)   "
                ;;
            queued)
                echo -ne "\r    ⏳ Queued... (${elapsed}s/${POLL_TIMEOUT}s)    "
                ;;
        esac
    done
    echo ""

    if [ "$final_status" = "queued" ] || [ "$final_status" = "running" ]; then
        log_fail "Job timed out after ${POLL_TIMEOUT}s (status: ${final_status})"
        return 1
    fi
}

phase_lifecycle() {
    log_header "Phase 4: Ticket Lifecycle (real projects)"

    # Pick real projects that have Python files
    local test_projects=()
    for proj in "${PROJECTS_ROOT}/proxy" "${PROJECTS_ROOT}/code2llm" "${PROJECTS_ROOT}/fraq" "${PROJECTS_ROOT}/coreskill" "${PROJECTS_ROOT}/toonic"; do
        if [ -d "$proj" ]; then
            test_projects+=("$proj")
        fi
    done

    if [ ${#test_projects[@]} -eq 0 ]; then
        log_warn "No test projects found in ${PROJECTS_ROOT}"
        return
    fi

    log_info "Found ${#test_projects[@]} test projects: ${test_projects[*]##*/}"

    # Determine which tools to test
    local tools_to_test
    if [ -n "$TOOL_FILTER" ] && [ "$TOOL_FILTER" != "--quick" ]; then
        tools_to_test="${TOOL_FILTER#--tool=}"
        tools_to_test="${tools_to_test#--tool }"
    else
        # Test tools that are likely available: shell-based ones first
        tools_to_test="roo-code cline"
    fi

    local proj_idx=0
    for tool in $tools_to_test; do
        local proj="${test_projects[$((proj_idx % ${#test_projects[@]}))]}"
        local proj_name
        proj_name=$(basename "$proj")

        dispatch_and_monitor "$tool" "$proj" \
            "Analyze the project structure of ${proj_name} and list the main modules and their responsibilities"

        proj_idx=$((proj_idx + 1))
    done
}

# ── Phase 5: Queue & Logs Validation ─────────────────────

phase_queue_logs() {
    log_header "Phase 5: Queue & Logs Validation"

    log_test "Checking queue after dispatches"
    parse_response "$(api_get /dashboard/tools/queue)"
    if [ "$HTTP_CODE" = "200" ]; then
        local total running_flag by_status
        total=$(jq_field '.total_jobs')
        running_flag=$(jq_field '.running')
        by_status=$(echo "$BODY" | jq -c '.by_status' 2>/dev/null)
        log_pass "Queue summary: total=${total}, running=${running_flag}, status=${by_status}"
    else
        log_fail "Queue endpoint failed"
    fi

    log_test "Checking recent jobs"
    parse_response "$(api_get "/dashboard/tools/queue/jobs?limit=10")"
    if [ "$HTTP_CODE" = "200" ]; then
        local job_count
        job_count=$(jq_field '.count')
        log_pass "Jobs listing OK (${job_count} recent jobs)"

        # Show job details
        echo "$BODY" | jq -r '.jobs[] | "    \(.id) | \(.tool) | \(.status) | \(.duration_s)s"' 2>/dev/null | head -10
    else
        log_fail "Jobs listing failed (HTTP ${HTTP_CODE})"
    fi

    log_test "Checking system logs for tool events"
    parse_response "$(api_get "/dashboard/logs?lines=100")"
    if [ "$HTTP_CODE" = "200" ]; then
        local log_lines
        # Endpoint may return .logs[] or .lines[] depending on version
        log_lines=$(echo "$BODY" | jq -r '(.logs // .lines // [])[]' 2>/dev/null || echo "")
        local tool_log_count=0
        if [ -n "$log_lines" ]; then
            tool_log_count=$(echo "$log_lines" | grep -c "tool_" 2>/dev/null || true)
        fi
        if [ "$tool_log_count" -gt 0 ] 2>/dev/null; then
            log_pass "Found ${tool_log_count} tool-related log entries"
            echo "$log_lines" | grep "tool_" | tail -5 | while read -r line; do
                echo -e "    ${YELLOW}${line}${NC}"
            done
        else
            log_warn "No tool-related log entries found in recent logs"
        fi
    else
        log_warn "Logs endpoint returned HTTP ${HTTP_CODE}"
    fi
}

# ── Phase 6: Tickets Consistency ──────────────────────────

phase_tickets() {
    log_header "Phase 6: Tickets Consistency"

    log_test "Listing all tickets"
    parse_response "$(api_get /dashboard/tickets)"
    if [ "$HTTP_CODE" != "200" ]; then
        log_fail "Tickets endpoint failed (HTTP ${HTTP_CODE})"
        return
    fi

    local ticket_count
    ticket_count=$(echo "$BODY" | jq '.tickets | length' 2>/dev/null)
    log_pass "Total tickets: ${ticket_count}"

    # Check validation tickets
    local validation_tickets
    validation_tickets=$(echo "$BODY" | jq '[.tickets[] | select(.tags[]? == "validation")]' 2>/dev/null)
    local validation_count
    validation_count=$(echo "$validation_tickets" | jq 'length' 2>/dev/null)
    log_info "Validation tickets: ${validation_count}"

    # Check for tickets stuck in queued state
    local stuck_queued
    stuck_queued=$(echo "$BODY" | jq '[.tickets[] | select(.last_job.status == "queued")] | length' 2>/dev/null)
    if [ "$stuck_queued" -gt 0 ] 2>/dev/null; then
        log_warn "${stuck_queued} tickets stuck in 'queued' state"
    else
        log_pass "No tickets stuck in queued state"
    fi

    # Check for failed tickets
    local failed_count
    failed_count=$(echo "$BODY" | jq '[.tickets[] | select(.last_job.status == "failed")] | length' 2>/dev/null)
    if [ "$failed_count" -gt 0 ] 2>/dev/null; then
        log_warn "${failed_count} tickets with failed jobs"
        echo "$BODY" | jq -r '.tickets[] | select(.last_job.status == "failed") | "    \(.id) | \(.last_job.tool) | \(.last_job.error[:80])"' 2>/dev/null
    fi

    # Board view
    log_test "Checking kanban board"
    parse_response "$(api_get /dashboard/tickets/board/view)"
    if [ "$HTTP_CODE" = "200" ]; then
        log_pass "Board view OK"
        for col in backlog todo in_progress in_review done cancelled; do
            local count
            count=$(echo "$BODY" | jq ".${col} | length" 2>/dev/null || echo 0)
            [ "$count" != "0" ] && log_info "  ${col}: ${count}"
        done
    else
        log_warn "Board view failed (HTTP ${HTTP_CODE})"
    fi
}

# ── Summary ───────────────────────────────────────────────

summary() {
    log_header "Validation Summary"
    echo -e "  ${GREEN}PASS: ${PASS}${NC}"
    echo -e "  ${RED}FAIL: ${FAIL}${NC}"
    echo -e "  ${YELLOW}WARN: ${WARN}${NC}"
    echo ""

    if [ $FAIL -eq 0 ]; then
        echo -e "  ${GREEN}🎉 All critical checks passed!${NC}"
        exit 0
    else
        echo -e "  ${RED}💥 ${FAIL} check(s) failed — see details above${NC}"
        exit 1
    fi
}

# ── Main ──────────────────────────────────────────────────

echo -e "${CYAN}╔═══════════════════════════════════════════════════╗${NC}"
echo -e "${CYAN}║    proxym System Validation                       ║${NC}"
echo -e "${CYAN}║    URL: ${PROXYM_URL}                       ║${NC}"
echo -e "${CYAN}╚═══════════════════════════════════════════════════╝${NC}"

phase_health

if [ "$TOOL_FILTER" = "--quick" ]; then
    phase_tools
    phase_executor
    summary
fi

# Disable set -e for validation phases so we always reach summary
set +e
phase_tools
phase_executor
phase_lifecycle
phase_queue_logs
phase_tickets
set -e
summary
