#!/bin/bash

# Graphorama MCP Installation Verification Script
# Tests installation, configuration, and MCP client integration

set -euo pipefail

VERSION="1.0.0"
SCRIPT_NAME=$(basename "$0")

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
BOLD='\033[1m'
NC='\033[0m' # No Color

# Test results
TESTS_PASSED=0
TESTS_FAILED=0
WARNINGS=0

# Configuration
BINARY_NAME="graphorama"
TIMEOUT_SECONDS=10
VERBOSE=false

# Print functions
print_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
print_success() { echo -e "${GREEN}[✅ PASS]${NC} $1"; }
print_warning() { echo -e "${YELLOW}[⚠️  WARN]${NC} $1"; }
print_error() { echo -e "${RED}[❌ FAIL]${NC} $1" >&2; }
print_bold() { echo -e "${BOLD}$1${NC}"; }

# Increment counters
pass_test() {
    ((TESTS_PASSED++))
    print_success "$1"
}

fail_test() {
    ((TESTS_FAILED++))
    print_error "$1"
}

warn_test() {
    ((WARNINGS++))
    print_warning "$1"
}

# Verbose logging
log_verbose() {
    if [[ "$VERBOSE" == "true" ]]; then
        print_info "$1"
    fi
}

# Help function
show_help() {
cat << EOF
$SCRIPT_NAME v$VERSION - Graphorama Installation Verifier

USAGE:
    $SCRIPT_NAME [OPTIONS]

DESCRIPTION:
    Comprehensive verification of Graphorama MCP installation.
    Tests binary installation, MCP protocol compliance, client integration,
    and performance characteristics.

OPTIONS:
    -b, --binary-path PATH      Path to graphorama binary (default: auto-detect)
    -t, --timeout SECONDS       Timeout for tests (default: 10)
    -v, --verbose               Enable verbose output
    -q, --quiet                 Only show final results
    --skip-mcp                  Skip MCP protocol tests
    --skip-performance          Skip performance tests
    --skip-clients              Skip MCP client detection tests
    -h, --help                  Show this help message
    --version                   Show version information

TEST CATEGORIES:
    🔍 Binary Tests
        ✓ Binary exists and is executable
        ✓ Version information available
        ✓ Help text accessible
        ✓ Basic command validation

    🔌 MCP Protocol Tests
        ✓ MCP server startup
        ✓ Protocol version compliance
        ✓ Tool list availability
        ✓ Initialize request/response
        ✓ Tool execution capability

    ⚡ Performance Tests  
        ✓ Startup time measurement
        ✓ Memory usage analysis
        ✓ Response time benchmarks
        ✓ Cache performance

    🖥️  Client Integration Tests
        ✓ Detect available MCP clients
        ✓ Validate configuration files
        ✓ Test wrapper scripts
        ✓ Verify client compatibility

EXAMPLES:
    # Basic verification
    $SCRIPT_NAME

    # Verbose verification with custom binary
    $SCRIPT_NAME --verbose --binary-path /opt/graphorama/bin/graphorama

    # Quick check (skip performance tests)  
    $SCRIPT_NAME --quiet --skip-performance

    # MCP protocol only
    $SCRIPT_NAME --skip-clients --skip-performance

EXIT CODES:
    0  - All tests passed
    1  - Some tests failed (warnings may exist)  
    2  - Critical failures (binary not found, etc.)

EOF
}

# Parse command line arguments
parse_args() {
    BINARY_PATH=""
    SKIP_MCP=false
    SKIP_PERFORMANCE=false
    SKIP_CLIENTS=false
    QUIET=false
    
    while [[ $# -gt 0 ]]; do
        case $1 in
            -b|--binary-path)
                BINARY_PATH="$2"
                shift 2
                ;;
            -t|--timeout)
                TIMEOUT_SECONDS="$2"
                shift 2
                ;;
            -v|--verbose)
                VERBOSE=true
                shift
                ;;
            -q|--quiet)
                QUIET=true
                shift
                ;;
            --skip-mcp)
                SKIP_MCP=true
                shift
                ;;
            --skip-performance)
                SKIP_PERFORMANCE=true
                shift
                ;;
            --skip-clients)
                SKIP_CLIENTS=true
                shift
                ;;
            -h|--help)
                show_help
                exit 0
                ;;
            --version)
                echo "$SCRIPT_NAME v$VERSION"
                exit 0
                ;;
            *)
                print_error "Unknown option: $1"
                echo "Use --help for usage information."
                exit 1
                ;;
        esac
    done
}

# Find graphorama binary
find_binary() {
    if [[ -n "$BINARY_PATH" ]]; then
        if [[ ! -f "$BINARY_PATH" ]]; then
            print_error "Specified binary not found: $BINARY_PATH"
            exit 2
        fi
        echo "$BINARY_PATH"
        return 0
    fi
    
    # Check common locations
    local locations=(
        "/usr/local/bin/$BINARY_NAME"
        "/usr/bin/$BINARY_NAME" 
        "$HOME/bin/$BINARY_NAME"
        "$HOME/.local/bin/$BINARY_NAME"
        "./target/release/$BINARY_NAME"
        "./$BINARY_NAME"
    )
    
    # Check PATH first
    if command -v "$BINARY_NAME" >/dev/null 2>&1; then
        which "$BINARY_NAME"
        return 0
    fi
    
    # Check specific locations
    for location in "${locations[@]}"; do
        if [[ -f "$location" ]]; then
            echo "$location"
            return 0
        fi
    done
    
    print_error "Graphorama binary not found. Please specify path with --binary-path"
    exit 2
}

# Test binary basics
test_binary() {
    if [[ "$QUIET" != true ]]; then
        print_bold "🔍 Testing Binary Installation"
    fi
    
    local binary_path="$1"
    
    # Test 1: Binary exists and is executable
    if [[ -x "$binary_path" ]]; then
        pass_test "Binary exists and is executable"
    else
        fail_test "Binary is not executable: $binary_path"
        return 1
    fi
    
    # Test 2: Version information
    log_verbose "Testing version command..."
    if timeout "$TIMEOUT_SECONDS" "$binary_path" --version >/dev/null 2>&1; then
        local version_output
        version_output=$("$binary_path" --version)
        pass_test "Version information available: $version_output"
    else
        fail_test "Cannot get version information"
    fi
    
    # Test 3: Help text
    log_verbose "Testing help command..."
    if timeout "$TIMEOUT_SECONDS" "$binary_path" --help >/dev/null 2>&1; then
        pass_test "Help text accessible"
    else
        fail_test "Cannot access help text"
    fi
    
    # Test 4: Invalid command handling
    log_verbose "Testing invalid command handling..."
    if "$binary_path" --invalid-command-xyz >/dev/null 2>&1; then
        warn_test "Binary accepts invalid commands (may be normal)"
    else
        pass_test "Invalid commands properly rejected"
    fi
}

# Test MCP protocol compliance
test_mcp_protocol() {
    if [[ "$SKIP_MCP" == true ]]; then
        return 0
    fi
    
    if [[ "$QUIET" != true ]]; then
        print_bold "🔌 Testing MCP Protocol Compliance"
    fi
    
    local binary_path="$1"
    local temp_dir
    temp_dir=$(mktemp -d)
    
    # Start server in background
    log_verbose "Starting MCP server..."
    timeout "$TIMEOUT_SECONDS" "$binary_path" serve --transport stdio > "$temp_dir/server.log" 2>&1 &
    local server_pid=$!
    
    # Give server time to start
    sleep 1
    
    # Test 1: Initialize request
    log_verbose "Testing initialize request..."
    local init_request='{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}'
    local init_response
    
    if init_response=$(echo "$init_request" | timeout "$TIMEOUT_SECONDS" "$binary_path" serve --transport stdio 2>/dev/null); then
        if echo "$init_response" | jq -e '.result | has("protocolVersion") and has("capabilities") and has("serverInfo")' >/dev/null 2>&1; then
            pass_test "Initialize request/response working"
        else
            fail_test "Initialize response format invalid"
        fi
    else
        fail_test "Initialize request failed"
    fi
    
    # Test 2: Tools list
    log_verbose "Testing tools list..."
    local tools_request='{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}'
    local tools_response
    
    if tools_response=$(echo "$tools_request" | timeout "$TIMEOUT_SECONDS" "$binary_path" serve --transport stdio 2>/dev/null); then
        if echo "$tools_response" | jq -e '.result.tools | length > 0' >/dev/null 2>&1; then
            local tool_count
            tool_count=$(echo "$tools_response" | jq '.result.tools | length')
            pass_test "Tools list available: $tool_count tools"
            
            # Verify expected tools
            local expected_tools=("validate_changes" "discover_services" "get_cache_stats" "watch_path" "validate_contract" "validate_cross_service" "run_integration_tests")
            local missing_tools=()
            
            for tool in "${expected_tools[@]}"; do
                if ! echo "$tools_response" | jq -e ".result.tools[] | select(.name == \"$tool\")" >/dev/null 2>&1; then
                    missing_tools+=("$tool")
                fi
            done
            
            if [[ ${#missing_tools[@]} -eq 0 ]]; then
                pass_test "All expected tools present"
            else
                warn_test "Missing tools: ${missing_tools[*]}"
            fi
        else
            fail_test "No tools available"
        fi
    else
        fail_test "Tools list request failed"
    fi
    
    # Test 3: Tool execution (simple test)
    log_verbose "Testing tool execution..."
    local tool_request='{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"get_cache_stats","arguments":{}}}'
    local tool_response
    
    if tool_response=$(echo "$tool_request" | timeout "$TIMEOUT_SECONDS" "$binary_path" serve --transport stdio 2>/dev/null); then
        if echo "$tool_response" | jq -e '.result | has("content")' >/dev/null 2>&1; then
            pass_test "Tool execution working"
        else
            warn_test "Tool execution response format unexpected"
        fi
    else
        warn_test "Tool execution test failed (may be normal for cache_stats without setup)"
    fi
    
    # Cleanup
    kill $server_pid 2>/dev/null || true
    wait $server_pid 2>/dev/null || true
    rm -rf "$temp_dir"
}

# Test performance characteristics
test_performance() {
    if [[ "$SKIP_PERFORMANCE" == true ]]; then
        return 0
    fi
    
    if [[ "$QUIET" != true ]]; then
        print_bold "⚡ Testing Performance Characteristics"
    fi
    
    local binary_path="$1"
    
    # Test 1: Startup time
    log_verbose "Testing startup time..."
    local total_time=0
    local iterations=5
    
    for ((i=1; i<=iterations; i++)); do
        local start_time end_time duration
        start_time=$(date +%s%N)
        "$binary_path" --version >/dev/null 2>&1
        end_time=$(date +%s%N)
        duration=$(( (end_time - start_time) / 1000000 )) # Convert to milliseconds
        total_time=$((total_time + duration))
        log_verbose "Startup $i: ${duration}ms"
    done
    
    local avg_startup=$((total_time / iterations))
    if [[ $avg_startup -lt 100 ]]; then
        pass_test "Startup time excellent: ${avg_startup}ms average"
    elif [[ $avg_startup -lt 500 ]]; then
        pass_test "Startup time good: ${avg_startup}ms average"
    else
        warn_test "Startup time slow: ${avg_startup}ms average (target: <100ms)"
    fi
    
    # Test 2: Memory usage
    log_verbose "Testing memory usage..."
    "$binary_path" serve --transport stdio >/dev/null 2>&1 &
    local server_pid=$!
    sleep 2
    
    if kill -0 $server_pid 2>/dev/null; then
        local memory_kb memory_mb
        if memory_kb=$(ps -o rss= -p $server_pid 2>/dev/null); then
            memory_mb=$((memory_kb / 1024))
            if [[ $memory_mb -lt 25 ]]; then
                pass_test "Memory usage excellent: ${memory_mb}MB"
            elif [[ $memory_mb -lt 50 ]]; then
                pass_test "Memory usage good: ${memory_mb}MB"
            else
                warn_test "Memory usage high: ${memory_mb}MB (target: <25MB)"
            fi
        else
            warn_test "Cannot measure memory usage"
        fi
        kill $server_pid 2>/dev/null || true
    else
        warn_test "Server process died during memory test"
    fi
    
    # Test 3: Response time
    log_verbose "Testing MCP response time..."
    local response_time_ms
    local start_time end_time
    
    start_time=$(date +%s%N)
    echo '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' | timeout "$TIMEOUT_SECONDS" "$binary_path" serve --transport stdio >/dev/null 2>&1 || true
    end_time=$(date +%s%N)
    response_time_ms=$(( (end_time - start_time) / 1000000 ))
    
    if [[ $response_time_ms -lt 50 ]]; then
        pass_test "MCP response time excellent: ${response_time_ms}ms"
    elif [[ $response_time_ms -lt 200 ]]; then
        pass_test "MCP response time good: ${response_time_ms}ms"
    else
        warn_test "MCP response time slow: ${response_time_ms}ms (target: <50ms)"
    fi
}

# Test MCP client integration
test_client_integration() {
    if [[ "$SKIP_CLIENTS" == true ]]; then
        return 0
    fi
    
    if [[ "$QUIET" != true ]]; then
        print_bold "🖥️  Testing MCP Client Integration"
    fi
    
    local found_clients=()
    
    # Test Claude Desktop
    if [[ -d "$HOME/Library/Application Support/Claude" ]] || [[ -d "$HOME/.config/Claude" ]] || [[ -d "$HOME/AppData/Roaming/Claude" ]]; then
        found_clients+=("Claude Desktop")
        
        # Check for existing configuration
        local config_files=(
            "$HOME/Library/Application Support/Claude/claude_desktop_config.json"
            "$HOME/.config/Claude/claude_desktop_config.json"
            "$HOME/AppData/Roaming/Claude/claude_desktop_config.json"
        )
        
        local configured=false
        for config_file in "${config_files[@]}"; do
            if [[ -f "$config_file" ]] && grep -q "graphorama" "$config_file" 2>/dev/null; then
                configured=true
                break
            fi
        done
        
        if [[ "$configured" == true ]]; then
            pass_test "Claude Desktop detected and configured"
        else
            warn_test "Claude Desktop detected but not configured for Graphorama"
        fi
    fi
    
    # Test Claude Code
    if command -v claude >/dev/null 2>&1; then
        found_clients+=("Claude Code")
        
        # Check if graphorama is configured
        if claude mcp list 2>/dev/null | grep -q "graphorama" 2>/dev/null; then
            pass_test "Claude Code detected and configured"
        else
            warn_test "Claude Code detected but not configured for Graphorama"
        fi
    fi
    
    # Test Cursor IDE
    if [[ -d "$HOME/.cursor" ]] || command -v cursor >/dev/null 2>&1; then
        found_clients+=("Cursor IDE")
        
        # Check for MCP configuration
        if [[ -f "$HOME/.cursor/mcp.json" ]] && grep -q "graphorama" "$HOME/.cursor/mcp.json" 2>/dev/null; then
            pass_test "Cursor IDE detected and configured"
        else
            warn_test "Cursor IDE detected but not configured for Graphorama"
        fi
    fi
    
    # Test Windsurf IDE
    if [[ -d "$HOME/.codeium/windsurf" ]] || command -v windsurf >/dev/null 2>&1; then
        found_clients+=("Windsurf IDE")
        
        # Check for MCP configuration
        if [[ -f "$HOME/.codeium/windsurf/mcp_config.json" ]] && grep -q "graphorama" "$HOME/.codeium/windsurf/mcp_config.json" 2>/dev/null; then
            pass_test "Windsurf IDE detected and configured"
        else
            warn_test "Windsurf IDE detected but not configured for Graphorama"
        fi
    fi
    
    # Test Gemini CLI
    if command -v gemini >/dev/null 2>&1; then
        found_clients+=("Gemini CLI")
        
        # Check for configuration
        local gemini_config=""
        if [[ -f "$HOME/.config/gemini-cli/settings.json" ]]; then
            gemini_config="$HOME/.config/gemini-cli/settings.json"
        elif [[ -f "$HOME/AppData/Roaming/gemini-cli/settings.json" ]]; then
            gemini_config="$HOME/AppData/Roaming/gemini-cli/settings.json"
        fi
        
        if [[ -n "$gemini_config" ]] && grep -q "graphorama" "$gemini_config" 2>/dev/null; then
            pass_test "Gemini CLI detected and configured"
        else
            warn_test "Gemini CLI detected but not configured for Graphorama"
        fi
    fi
    
    # Summary
    if [[ ${#found_clients[@]} -gt 0 ]]; then
        pass_test "Found MCP clients: ${found_clients[*]}"
    else
        warn_test "No MCP clients detected"
    fi
}

# Show final results
show_results() {
    echo
    print_bold "📊 Verification Results"
    echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
    
    if [[ $TESTS_PASSED -gt 0 ]]; then
        echo -e "${GREEN}✅ Tests Passed: $TESTS_PASSED${NC}"
    fi
    
    if [[ $TESTS_FAILED -gt 0 ]]; then
        echo -e "${RED}❌ Tests Failed: $TESTS_FAILED${NC}"
    fi
    
    if [[ $WARNINGS -gt 0 ]]; then
        echo -e "${YELLOW}⚠️  Warnings: $WARNINGS${NC}"
    fi
    
    echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
    
    # Overall status
    if [[ $TESTS_FAILED -eq 0 ]]; then
        if [[ $WARNINGS -eq 0 ]]; then
            print_bold "🎉 Installation is PERFECT! All tests passed."
        else
            print_bold "✅ Installation is GOOD with minor warnings."
        fi
        echo
        echo "Graphorama MCP server is ready to use!"
        echo
        echo "Next steps:"
        echo "• Configure your MCP client (see warnings above for guidance)"
        echo "• Test with: 'Can you validate this code for me?'"
        echo "• Read documentation: https://github.com/nedops/grapharoma-mcp"
    else
        print_bold "❌ Installation has ISSUES that need attention."
        echo
        echo "Common fixes:"
        echo "• Ensure graphorama binary is in PATH"
        echo "• Check file permissions: chmod +x /path/to/graphorama"
        echo "• Verify MCP client configuration"
        echo "• See https://github.com/nedops/grapharoma-mcp/blob/main/docs/troubleshooting.md"
    fi
    
    echo
}

# Main execution
main() {
    # Parse arguments
    parse_args "$@"
    
    if [[ "$QUIET" != true ]]; then
        print_bold "🔍 Graphorama MCP Installation Verifier v$VERSION"
        echo
    fi
    
    # Find binary
    local binary_path
    binary_path=$(find_binary)
    log_verbose "Using binary: $binary_path"
    
    # Run test suites
    test_binary "$binary_path"
    test_mcp_protocol "$binary_path"
    test_performance "$binary_path"
    test_client_integration
    
    # Show results
    show_results
    
    # Exit with appropriate code
    if [[ $TESTS_FAILED -gt 0 ]]; then
        exit 1
    else
        exit 0
    fi
}

# Check for required tools
check_requirements() {
    local missing_tools=()
    
    if ! command -v jq >/dev/null 2>&1; then
        missing_tools+=("jq")
    fi
    
    if ! command -v timeout >/dev/null 2>&1; then
        missing_tools+=("timeout")
    fi
    
    if [[ ${#missing_tools[@]} -gt 0 ]]; then
        print_error "Missing required tools: ${missing_tools[*]}"
        echo "Please install the missing tools and try again."
        echo
        echo "Installation commands:"
        echo "• macOS: brew install jq coreutils"
        echo "• Ubuntu/Debian: sudo apt-get install jq coreutils"
        echo "• CentOS/RHEL: sudo yum install jq coreutils"
        exit 2
    fi
}

# Run verification
check_requirements
main "$@"