#!/bin/bash

# ClawRouter Edge Case Test Suite
# Tests OpenClaw integration, model routing, error handling, and x402 flows

set -e

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

PASSED=0
FAILED=0
SKIPPED=0

CLAWROUTER_PORT=8402
BLOCKRUN_API="https://api.blockrun.ai/v1"

log_section() {
    echo ""
    echo -e "${CYAN}╔══════════════════════════════════════════════════════════════╗${NC}"
    echo -e "${CYAN}║ $1${NC}"
    echo -e "${CYAN}╚══════════════════════════════════════════════════════════════╝${NC}"
}

log_test() {
    echo -e "${BLUE}━━━ TEST $1: $2${NC}"
}

log_pass() {
    echo -e "  ${GREEN}✓ PASS${NC}: $1"
    ((PASSED++))
}

log_fail() {
    echo -e "  ${RED}✗ FAIL${NC}: $1"
    ((FAILED++))
}

log_skip() {
    echo -e "  ${YELLOW}⊘ SKIP${NC}: $1"
    ((SKIPPED++))
}

log_info() {
    echo -e "  ${NC}$1${NC}"
}

wait_for_port() {
    local port=$1
    local timeout=${2:-30}
    local count=0
    while ! nc -z localhost $port 2>/dev/null; do
        sleep 1
        ((count++))
        if [ $count -ge $timeout ]; then
            return 1
        fi
    done
    return 0
}

# ═══════════════════════════════════════════════════════════════
# SECTION 1: Installation Edge Cases
# ═══════════════════════════════════════════════════════════════

test_fresh_install() {
    log_test "1.1" "Fresh installation from npm"

    npm install -g @blockrun/clawrouter 2>&1 | head -5

    if command -v clawrouter &> /dev/null; then
        log_pass "ClawRouter installed"
        clawrouter --version
    else
        log_fail "ClawRouter not in PATH"
        return 1
    fi
}

test_dist_files_exist() {
    log_test "1.2" "Verify dist/ files included in package"

    PKG_DIR=$(npm root -g)/@blockrun/clawrouter

    local files=("dist/index.js" "dist/cli.js" "dist/index.d.ts")
    local all_exist=true

    for f in "${files[@]}"; do
        if [ -f "$PKG_DIR/$f" ]; then
            log_info "Found: $f"
        else
            log_fail "Missing: $f"
            all_exist=false
        fi
    done

    if $all_exist; then
        log_pass "All dist/ files present"
    else
        return 1
    fi
}

test_openclaw_plugin_install() {
    log_test "1.3" "OpenClaw plugin installation via reinstall script"

    # Run the reinstall script
    bash $(npm root -g)/@blockrun/clawrouter/scripts/reinstall.sh 2>&1 || {
        log_fail "Reinstall script failed"
        return 1
    }

    # Verify extension installed
    if [ -f "$HOME/.openclaw/extensions/clawrouter/dist/index.js" ]; then
        log_pass "OpenClaw extension installed correctly"
    else
        log_fail "Extension dist/index.js missing"
        return 1
    fi
}

# ═══════════════════════════════════════════════════════════════
# SECTION 2: Model Routing Edge Cases
# ═══════════════════════════════════════════════════════════════

test_model_alias_resolution() {
    log_test "2.1" "Model alias resolution"

    local aliases=(
        "gpt-4o:openai/gpt-4o"
        "sonnet:anthropic/claude-sonnet-4.6"
        "deepseek:deepseek/deepseek-chat"
        "gemini:google/gemini-2.5-flash"
        "free:gpt-oss-120b"
    )

    for alias_pair in "${aliases[@]}"; do
        local alias="${alias_pair%%:*}"
        local expected="${alias_pair##*:}"
        log_info "Testing alias: $alias → $expected"
    done

    log_pass "Alias mappings defined (runtime test requires proxy)"
}

test_blockrun_prefix_stripping() {
    log_test "2.2" "blockrun/ prefix stripping"

    # These models should all resolve correctly
    local models=(
        "blockrun/anthropic/claude-sonnet-4.6"
        "blockrun/openai/gpt-4o"
        "blockrun/deepseek/deepseek-chat"
        "anthropic/claude-sonnet-4.6"
        "gpt-4o"
    )

    for model in "${models[@]}"; do
        log_info "Model: $model"
    done

    log_pass "Prefix stripping patterns defined"
}

test_invalid_model_handling() {
    log_test "2.3" "Invalid model error handling"

    # Test with clearly invalid model
    local response
    response=$(curl -s -X POST "http://localhost:$CLAWROUTER_PORT/v1/chat/completions" \
        -H "Content-Type: application/json" \
        -d '{"model":"invalid/nonexistent-model","messages":[{"role":"user","content":"test"}]}' 2>/dev/null || echo '{"error":"proxy_not_running"}')

    if echo "$response" | jq -e '.error' &>/dev/null; then
        log_pass "Invalid model returns error response"
    else
        log_skip "Proxy not running for live test"
    fi
}

# ═══════════════════════════════════════════════════════════════
# SECTION 3: Proxy Lifecycle Edge Cases
# ═══════════════════════════════════════════════════════════════

test_proxy_startup() {
    log_test "3.1" "Proxy startup on port $CLAWROUTER_PORT"

    # Kill any existing proxy
    lsof -ti :$CLAWROUTER_PORT | xargs kill -9 2>/dev/null || true
    sleep 1

    # Start proxy in background
    BLOCKRUN_WALLET_KEY="0x$(openssl rand -hex 32)" clawrouter &
    PROXY_PID=$!

    if wait_for_port $CLAWROUTER_PORT 10; then
        log_pass "Proxy started on port $CLAWROUTER_PORT (PID: $PROXY_PID)"
    else
        log_fail "Proxy failed to start within 10s"
        kill $PROXY_PID 2>/dev/null || true
        return 1
    fi
}

test_proxy_health_check() {
    log_test "3.2" "Proxy health check endpoint"

    local response
    response=$(curl -s "http://localhost:$CLAWROUTER_PORT/health" 2>/dev/null || echo "failed")

    if [ "$response" != "failed" ]; then
        log_pass "Health endpoint responding"
        log_info "Response: $response"
    else
        log_skip "Proxy not responding"
    fi
}

test_proxy_models_endpoint() {
    log_test "3.3" "Proxy /v1/models endpoint"

    local response
    response=$(curl -s "http://localhost:$CLAWROUTER_PORT/v1/models" 2>/dev/null || echo '{"error":"failed"}')

    if echo "$response" | jq -e '.data' &>/dev/null; then
        local count=$(echo "$response" | jq '.data | length')
        log_pass "Models endpoint returns $count models"
    else
        log_skip "Models endpoint not available"
    fi
}

test_proxy_graceful_shutdown() {
    log_test "3.4" "Proxy graceful shutdown"

    local pid=$(lsof -ti :$CLAWROUTER_PORT 2>/dev/null || echo "")

    if [ -n "$pid" ]; then
        kill $pid 2>/dev/null
        sleep 2

        if ! nc -z localhost $CLAWROUTER_PORT 2>/dev/null; then
            log_pass "Proxy shut down gracefully"
        else
            log_fail "Proxy still running after SIGTERM"
            kill -9 $pid 2>/dev/null || true
        fi
    else
        log_skip "No proxy running to test shutdown"
    fi
}

test_port_conflict_handling() {
    log_test "3.5" "Port conflict handling"

    # Start a dummy server on the port
    nc -l -p $CLAWROUTER_PORT &
    NC_PID=$!
    sleep 1

    # Try to start clawrouter (should fail or use different port)
    BLOCKRUN_WALLET_KEY="0x$(openssl rand -hex 32)" timeout 5 clawrouter 2>&1 | head -3 || true

    kill $NC_PID 2>/dev/null || true
    log_pass "Port conflict handled without crash"
}

# ═══════════════════════════════════════════════════════════════
# SECTION 4: Wallet & x402 Edge Cases
# ═══════════════════════════════════════════════════════════════

test_wallet_generation() {
    log_test "4.1" "Auto wallet generation"

    # Remove any existing wallet
    rm -f ~/.clawrouter/wallet.json 2>/dev/null || true

    # Start proxy briefly to generate wallet
    BLOCKRUN_WALLET_KEY="" timeout 3 clawrouter 2>&1 | head -5 || true

    if [ -f ~/.clawrouter/wallet.json ]; then
        log_pass "Wallet auto-generated"
        jq -r '.address' ~/.clawrouter/wallet.json | head -1
    else
        log_info "Wallet stored in memory only (expected for ephemeral mode)"
        log_pass "Wallet generation handled"
    fi
}

test_wallet_persistence() {
    log_test "4.2" "Wallet address persistence across restarts"

    local test_key="0x$(openssl rand -hex 32)"
    local addr1 addr2

    get_wallet_from_health() {
        local key="$1"
        local pid response wallet

        lsof -ti :$CLAWROUTER_PORT | xargs kill -9 2>/dev/null || true
        sleep 1

        BLOCKRUN_WALLET_KEY="$key" clawrouter >/tmp/clawrouter-wallet-persistence.log 2>&1 &
        pid=$!

        if ! wait_for_port $CLAWROUTER_PORT 10; then
            kill $pid 2>/dev/null || true
            wait $pid 2>/dev/null || true
            echo ""
            return 1
        fi

        response=$(curl -s "http://localhost:$CLAWROUTER_PORT/health" 2>/dev/null || echo "")
        wallet=$(echo "$response" | jq -r '.wallet // empty' 2>/dev/null || echo "")

        kill $pid 2>/dev/null || true
        wait $pid 2>/dev/null || true
        sleep 1

        echo "$wallet"
    }

    # Start proxy twice with the same key and compare reported wallet addresses.
    addr1=$(get_wallet_from_health "$test_key" || echo "")
    addr2=$(get_wallet_from_health "$test_key" || echo "")

    if [ -z "$addr1" ] || [ -z "$addr2" ]; then
        log_skip "Could not fetch wallet from /health for persistence check"
    elif [ "$addr1" = "$addr2" ]; then
        log_pass "Same key produces same address"
    else
        log_fail "Same key produced different addresses ($addr1 vs $addr2)"
        return 1
    fi
}

test_insufficient_balance() {
    log_test "4.3" "Insufficient balance error handling"

    # Start proxy with empty wallet
    lsof -ti :$CLAWROUTER_PORT | xargs kill -9 2>/dev/null || true
    sleep 1

    BLOCKRUN_WALLET_KEY="0x$(openssl rand -hex 32)" clawrouter &
    PROXY_PID=$!

    if wait_for_port $CLAWROUTER_PORT 10; then
        # Try a request (should fail with balance error)
        local response
        response=$(curl -s -X POST "http://localhost:$CLAWROUTER_PORT/v1/chat/completions" \
            -H "Content-Type: application/json" \
            -d '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"hi"}],"max_tokens":5}' 2>/dev/null || echo '{}')

        if echo "$response" | grep -qi "balance\|insufficient\|payment\|402"; then
            log_pass "Insufficient balance error returned correctly"
        else
            log_info "Response: $(echo "$response" | head -c 200)"
            log_skip "May have balance or API returned different error"
        fi

        kill $PROXY_PID 2>/dev/null || true
    else
        log_fail "Proxy didn't start for balance test"
    fi
}

# ═══════════════════════════════════════════════════════════════
# SECTION 5: Error Recovery Edge Cases
# ═══════════════════════════════════════════════════════════════

test_network_timeout_handling() {
    log_test "5.1" "Network timeout handling"

    # This would need a mock server to properly test
    log_skip "Requires mock server setup"
}

test_malformed_request_handling() {
    log_test "5.2" "Malformed request handling"

    lsof -ti :$CLAWROUTER_PORT | xargs kill -9 2>/dev/null || true
    sleep 1

    BLOCKRUN_WALLET_KEY="0x$(openssl rand -hex 32)" clawrouter &
    PROXY_PID=$!

    if wait_for_port $CLAWROUTER_PORT 10; then
        # Send malformed JSON
        local response
        response=$(curl -s -X POST "http://localhost:$CLAWROUTER_PORT/v1/chat/completions" \
            -H "Content-Type: application/json" \
            -d 'not valid json at all' 2>/dev/null || echo '{}')

        if echo "$response" | jq -e '.error' &>/dev/null; then
            log_pass "Malformed request returns error"
        else
            log_pass "Proxy handled malformed input without crash"
        fi

        kill $PROXY_PID 2>/dev/null || true
    else
        log_skip "Proxy not running"
    fi
}

test_empty_messages_array() {
    log_test "5.3" "Empty messages array handling"

    lsof -ti :$CLAWROUTER_PORT | xargs kill -9 2>/dev/null || true
    sleep 1

    BLOCKRUN_WALLET_KEY="0x$(openssl rand -hex 32)" clawrouter &
    PROXY_PID=$!

    if wait_for_port $CLAWROUTER_PORT 10; then
        local response
        response=$(curl -s -X POST "http://localhost:$CLAWROUTER_PORT/v1/chat/completions" \
            -H "Content-Type: application/json" \
            -d '{"model":"gpt-4o-mini","messages":[]}' 2>/dev/null || echo '{}')

        if echo "$response" | jq -e '.error' &>/dev/null; then
            log_pass "Empty messages returns appropriate error"
        else
            log_info "Response: $(echo "$response" | head -c 100)"
            log_pass "Empty messages handled"
        fi

        kill $PROXY_PID 2>/dev/null || true
    else
        log_skip "Proxy not running"
    fi
}

test_missing_model_field() {
    log_test "5.4" "Missing model field handling"

    lsof -ti :$CLAWROUTER_PORT | xargs kill -9 2>/dev/null || true
    sleep 1

    BLOCKRUN_WALLET_KEY="0x$(openssl rand -hex 32)" clawrouter &
    PROXY_PID=$!

    if wait_for_port $CLAWROUTER_PORT 10; then
        local response
        response=$(curl -s -X POST "http://localhost:$CLAWROUTER_PORT/v1/chat/completions" \
            -H "Content-Type: application/json" \
            -d '{"messages":[{"role":"user","content":"hi"}]}' 2>/dev/null || echo '{}')

        if echo "$response" | jq -e '.error' &>/dev/null; then
            log_pass "Missing model returns error"
        else
            log_info "May have used default model"
            log_pass "Missing model handled"
        fi

        kill $PROXY_PID 2>/dev/null || true
    else
        log_skip "Proxy not running"
    fi
}

# ═══════════════════════════════════════════════════════════════
# SECTION 6: OpenClaw Integration Edge Cases
# ═══════════════════════════════════════════════════════════════

test_openclaw_config_injection() {
    log_test "6.1" "OpenClaw config injection"

    CONFIG_FILE="$HOME/.openclaw/openclaw.json"

    if [ -f "$CONFIG_FILE" ]; then
        if jq -e '.models.providers.blockrun' "$CONFIG_FILE" &>/dev/null; then
            log_pass "blockrun provider configured in openclaw.json"
        else
            log_fail "blockrun provider not found in config"
        fi
    else
        log_skip "openclaw.json not found"
    fi
}

test_openclaw_auth_profile() {
    log_test "6.2" "OpenClaw auth profile setup"

    AUTH_FILE="$HOME/.openclaw/agents/main/agent/auth-profiles.json"

    if [ -f "$AUTH_FILE" ]; then
        if jq -e '.profiles["blockrun:default"]' "$AUTH_FILE" &>/dev/null; then
            log_pass "blockrun:default auth profile exists"
        else
            log_fail "blockrun:default profile not found"
        fi
    else
        log_skip "auth-profiles.json not found"
    fi
}

test_openclaw_plugins_allow() {
    log_test "6.3" "OpenClaw plugins.allow configuration"

    CONFIG_FILE="$HOME/.openclaw/openclaw.json"

    if [ -f "$CONFIG_FILE" ]; then
        if jq -e '.plugins.allow | index("clawrouter") or index("@blockrun/clawrouter")' "$CONFIG_FILE" &>/dev/null; then
            log_pass "clawrouter in plugins.allow"
        else
            log_fail "clawrouter not in plugins.allow"
        fi
    else
        log_skip "openclaw.json not found"
    fi
}

# ═══════════════════════════════════════════════════════════════
# SECTION 7: Cleanup & Summary
# ═══════════════════════════════════════════════════════════════

cleanup() {
    log_section "Cleanup"

    # Kill any running proxy
    lsof -ti :$CLAWROUTER_PORT | xargs kill -9 2>/dev/null || true

    log_info "Cleanup complete"
}

print_summary() {
    echo ""
    echo -e "${CYAN}╔══════════════════════════════════════════════════════════════╗${NC}"
    echo -e "${CYAN}║                      TEST SUMMARY                            ║${NC}"
    echo -e "${CYAN}╚══════════════════════════════════════════════════════════════╝${NC}"
    echo ""
    echo -e "  ${GREEN}Passed:  $PASSED${NC}"
    echo -e "  ${RED}Failed:  $FAILED${NC}"
    echo -e "  ${YELLOW}Skipped: $SKIPPED${NC}"
    echo ""

    if [ $FAILED -eq 0 ]; then
        echo -e "${GREEN}✓ All tests passed!${NC}"
        exit 0
    else
        echo -e "${RED}✗ Some tests failed${NC}"
        exit 1
    fi
}

# ═══════════════════════════════════════════════════════════════
# MAIN
# ═══════════════════════════════════════════════════════════════

main() {
    echo ""
    echo -e "${CYAN}╔══════════════════════════════════════════════════════════════╗${NC}"
    echo -e "${CYAN}║       ClawRouter Edge Case Test Suite v1.0                   ║${NC}"
    echo -e "${CYAN}║       OpenClaw + x402 Integration Testing                    ║${NC}"
    echo -e "${CYAN}╚══════════════════════════════════════════════════════════════╝${NC}"
    echo ""

    trap cleanup EXIT

    log_section "1. Installation Edge Cases"
    test_fresh_install || true
    test_dist_files_exist || true
    test_openclaw_plugin_install || true

    log_section "2. Model Routing Edge Cases"
    test_model_alias_resolution || true
    test_blockrun_prefix_stripping || true
    test_invalid_model_handling || true

    log_section "3. Proxy Lifecycle Edge Cases"
    test_proxy_startup || true
    test_proxy_health_check || true
    test_proxy_models_endpoint || true
    test_proxy_graceful_shutdown || true
    test_port_conflict_handling || true

    log_section "4. Wallet & x402 Edge Cases"
    test_wallet_generation || true
    test_wallet_persistence || true
    test_insufficient_balance || true

    log_section "5. Error Recovery Edge Cases"
    test_network_timeout_handling || true
    test_malformed_request_handling || true
    test_empty_messages_array || true
    test_missing_model_field || true

    log_section "6. OpenClaw Integration Edge Cases"
    test_openclaw_config_injection || true
    test_openclaw_auth_profile || true
    test_openclaw_plugins_allow || true

    print_summary
}

main "$@"
