#!/bin/bash

# ==============================================
# AzerothCore Docker Deployment & Health Check Script
# ==============================================
# This script deploys the complete AzerothCore stack and performs comprehensive health checks
# Usage: ./deploy-and-check.sh [--skip-deploy] [--quick-check] [--setup]

set -e  # Exit on any error

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

# Script options
SKIP_DEPLOY=false
QUICK_CHECK=false
RUN_SETUP=false
MODULES_ENABLED=false

# Parse command line arguments
while [[ $# -gt 0 ]]; do
    case $1 in
        --skip-deploy)
            SKIP_DEPLOY=true
            shift
            ;;
        --quick-check)
            QUICK_CHECK=true
            shift
            ;;
        --setup)
            RUN_SETUP=true
            shift
            ;;
        -h|--help)
            echo "Usage: $0 [--skip-deploy] [--quick-check] [--setup]"
            echo "  --skip-deploy    Skip deployment, only run health checks"
            echo "  --quick-check    Run basic health checks only"
            echo "  --setup          Run interactive server setup before deployment"
            exit 0
            ;;
        *)
            echo "Unknown option $1"
            exit 1
            ;;
    esac
done

# Function to print colored output
print_status() {
    local status=$1
    local message=$2
    case $status in
        "INFO")
            echo -e "${BLUE}ℹ️  ${message}${NC}"
            ;;
        "SUCCESS")
            echo -e "${GREEN}✅ ${message}${NC}"
            ;;
        "WARNING")
            echo -e "${YELLOW}⚠️  ${message}${NC}"
            ;;
        "ERROR")
            echo -e "${RED}❌ ${message}${NC}"
            ;;
        "HEADER")
            echo -e "\n${BLUE}=== ${message} ===${NC}"
            ;;
    esac
}

# Function to check if a port is accessible
check_port() {
    local port=$1
    local service_name=$2
    local timeout=${3:-5}

    if timeout $timeout bash -c "echo >/dev/tcp/localhost/$port" 2>/dev/null; then
        print_status "SUCCESS" "$service_name (port $port): CONNECTED"
        return 0
    else
        print_status "ERROR" "$service_name (port $port): FAILED"
        return 1
    fi
}

# Function to format seconds as MM:SS
format_time() {
    local total_seconds=$1
    local minutes=$((total_seconds / 60))
    local seconds=$((total_seconds % 60))
    printf "%d:%02d" "$minutes" "$seconds"
}

# Function to wait for a service to be ready
wait_for_service() {
    local service_name=$1
    local max_attempts=$2
    local check_command=$3
    local container_name=""

    # Extract container name from common patterns
    if echo "$check_command" | grep -q "ac-client-data"; then
        container_name="ac-client-data"
    elif echo "$check_command" | grep -q "ac-db-import"; then
        container_name="ac-db-import"
    elif echo "$check_command" | grep -q "ac-mysql"; then
        container_name="ac-mysql"
    elif echo "$check_command" | grep -q "ac-worldserver"; then
        container_name="ac-worldserver"
    elif echo "$check_command" | grep -q "ac-authserver"; then
        container_name="ac-authserver"
    fi

    local timeout_formatted=$(format_time $((max_attempts * 5)))
    print_status "INFO" "Waiting for $service_name to be ready... (timeout: $timeout_formatted)"

    for i in $(seq 1 $max_attempts); do
        if eval "$check_command" &>/dev/null; then
            print_status "SUCCESS" "$service_name is ready!"
            return 0
        fi

        if [ $i -eq $max_attempts ]; then
            print_status "ERROR" "$service_name failed to start after $max_attempts attempts"
            if [ -n "$container_name" ]; then
                print_status "INFO" "Last few log lines from $container_name:"
                docker logs "$container_name" --tail 5 2>/dev/null | sed 's/^/    /' || echo "    (no logs available)"
            fi
            return 1
        fi

        # Show progress with more informative output
        local elapsed=$((i * 5))
        local remaining=$(( (max_attempts - i) * 5))
        local elapsed_formatted=$(format_time $elapsed)
        local remaining_formatted=$(format_time $remaining)

        if [ -n "$container_name" ]; then
            # Get container status
            local status=$(docker inspect --format='{{.State.Status}}' "$container_name" 2>/dev/null || echo "unknown")
            local health=$(docker inspect --format='{{.State.Health.Status}}' "$container_name" 2>/dev/null || echo "no-health-check")

            # Show different progress info based on service
            case "$service_name" in
                "Client Data")
                    local last_log=$(docker logs "$container_name" --tail 1 2>/dev/null | head -c 80 || echo "...")
                    printf "${YELLOW}⏳${NC} %s elapsed, %s remaining | Status: %s | Latest: %s\n" "$elapsed_formatted" "$remaining_formatted" "$status" "$last_log"
                    ;;
                "Database Import")
                    printf "${YELLOW}⏳${NC} %s elapsed, %s remaining | Status: %s | Importing databases...\n" "$elapsed_formatted" "$remaining_formatted" "$status"
                    ;;
                *)
                    printf "${YELLOW}⏳${NC} %s elapsed, %s remaining | Status: %s" "$elapsed_formatted" "$remaining_formatted" "$status"
                    if [ "$health" != "no-health-check" ]; then
                        printf " | Health: %s" "$health"
                    fi
                    printf "\n"
                    ;;
            esac
        else
            printf "${YELLOW}⏳${NC} %s elapsed, %s remaining | Checking...\n" "$elapsed_formatted" "$remaining_formatted"
        fi

        sleep 5
    done
}

# Function to check container health
check_container_health() {
    local container_name=$1
    local status=$(docker inspect --format='{{.State.Health.Status}}' $container_name 2>/dev/null || echo "no-health-check")

    if [ "$status" = "healthy" ]; then
        print_status "SUCCESS" "$container_name: healthy"
        return 0
    elif [ "$status" = "no-health-check" ] || [ "$status" = "<no value>" ]; then
        # Check if container is running
        if docker ps --format '{{.Names}}' | grep -q "^${container_name}$"; then
            print_status "SUCCESS" "$container_name: running (no health check)"
            return 0
        else
            print_status "ERROR" "$container_name: not running"
            return 1
        fi
    else
        print_status "WARNING" "$container_name: $status"
        return 1
    fi
}

# Function to check web service health
check_web_service() {
    local url=$1
    local service_name=$2
    local expected_pattern=$3

    response=$(curl -s --max-time 10 "$url" 2>/dev/null || echo "")

    if [ -n "$expected_pattern" ]; then
        if echo "$response" | grep -q "$expected_pattern"; then
            print_status "SUCCESS" "$service_name: HTTP OK (content verified)"
            return 0
        else
            print_status "ERROR" "$service_name: HTTP OK but content verification failed"
            return 1
        fi
    else
        if [ -n "$response" ]; then
            print_status "SUCCESS" "$service_name: HTTP OK"
            return 0
        else
            print_status "ERROR" "$service_name: HTTP failed"
            return 1
        fi
    fi
}

# Function to deploy the stack
deploy_stack() {
    print_status "HEADER" "DEPLOYING AZEROTHCORE STACK"

    # Check if custom environment files exist first, then fallback to base files
    DB_ENV_FILE="./docker-compose-azerothcore-database-custom.env"
    SERVICES_ENV_FILE="./docker-compose-azerothcore-services-custom.env"
    MODULES_ENV_FILE="./docker-compose-azerothcore-modules-custom.env"
    TOOLS_ENV_FILE="./docker-compose-azerothcore-tools-custom.env"

    # Fallback to base files if custom files don't exist
    if [ ! -f "$DB_ENV_FILE" ]; then
        DB_ENV_FILE="./docker-compose-azerothcore-database.env"
    fi
    if [ ! -f "$SERVICES_ENV_FILE" ]; then
        SERVICES_ENV_FILE="./docker-compose-azerothcore-services.env"
    fi
    if [ ! -f "$MODULES_ENV_FILE" ]; then
        MODULES_ENV_FILE="./docker-compose-azerothcore-modules.env"
    fi
    if [ ! -f "$TOOLS_ENV_FILE" ]; then
        TOOLS_ENV_FILE="./docker-compose-azerothcore-tools.env"
    fi

    # Check if required environment files exist
    for env_file in "$DB_ENV_FILE" "$SERVICES_ENV_FILE" "$TOOLS_ENV_FILE"; do
        if [ ! -f "$env_file" ]; then
            print_status "ERROR" "Environment file $env_file not found"
            print_status "INFO" "Run ./scripts/setup-server.sh first to create environment files"
            exit 1
        fi
    done

    # Check if modules are enabled (set global variable)
    if [ -f "$MODULES_ENV_FILE" ]; then
        MODULES_ENABLED=true
    else
        MODULES_ENABLED=false
    fi

    print_status "INFO" "Step 1: Deploying database layer..."
    docker compose --env-file "$DB_ENV_FILE" -f ./docker-compose-azerothcore-database.yml up -d --remove-orphans

    # Wait for database initialization
    wait_for_service "MySQL" 24 "docker exec ac-mysql mysql -uroot -pazerothcore123 -e 'SELECT 1' >/dev/null 2>&1"

    # Wait for database import (can succeed with backup restore OR fail without backup)
    print_status "INFO" "Waiting for Database Import to complete (backup restore attempt)..."

    local import_result=""
    local elapsed=0
    local max_time=180  # 3 minutes max for import to complete

    while [ $elapsed -lt $max_time ]; do
        local import_status=$(docker inspect ac-db-import --format='{{.State.Status}}' 2>/dev/null || echo "unknown")

        if [ "$import_status" = "exited" ]; then
            local exit_code=$(docker inspect ac-db-import --format='{{.State.ExitCode}}' 2>/dev/null || echo "unknown")
            if [ "$exit_code" = "0" ]; then
                print_status "SUCCESS" "Database Import completed successfully (backup restored)"
                import_result="restored"
                break
            else
                print_status "INFO" "Database Import failed (no valid backup found - expected for fresh setup)"
                import_result="failed"
                break
            fi
        fi

        printf "${YELLOW}⏳${NC} ${elapsed}s elapsed, $((max_time - elapsed))s remaining | Status: $import_status | Checking for backup...\n"
        sleep 5
        elapsed=$((elapsed + 5))
    done

    if [ -z "$import_result" ]; then
        print_status "ERROR" "Database Import did not complete within timeout"
        exit 1
    fi

    # If import failed (no backup), wait for init to create databases
    if [ "$import_result" = "failed" ]; then
        print_status "INFO" "Waiting for Database Init to create fresh databases..."
        local init_elapsed=0
        local init_max_time=120  # 2 minutes for init

        while [ $init_elapsed -lt $init_max_time ]; do
            local init_status=$(docker inspect ac-db-init --format='{{.State.Status}}' 2>/dev/null || echo "created")

            if [ "$init_status" = "exited" ]; then
                local init_exit_code=$(docker inspect ac-db-init --format='{{.State.ExitCode}}' 2>/dev/null || echo "unknown")
                if [ "$init_exit_code" = "0" ]; then
                    print_status "SUCCESS" "Database Init completed successfully (fresh databases created)"
                    break
                else
                    print_status "ERROR" "Database Init failed"
                    print_status "INFO" "Last few log lines from ac-db-init:"
                    docker logs ac-db-init --tail 10 2>/dev/null || true
                    exit 1
                fi
            elif [ "$init_status" = "running" ]; then
                printf "${YELLOW}⏳${NC} ${init_elapsed}s elapsed, $((init_max_time - init_elapsed))s remaining | Status: $init_status | Creating databases...\n"
            else
                printf "${YELLOW}⏳${NC} ${init_elapsed}s elapsed, $((init_max_time - init_elapsed))s remaining | Status: $init_status | Waiting to start...\n"
            fi

            sleep 5
            init_elapsed=$((init_elapsed + 5))
        done

        if [ $init_elapsed -ge $init_max_time ]; then
            print_status "ERROR" "Database Init did not complete within timeout"
            exit 1
        fi
    fi

    print_status "INFO" "Step 2: Deploying services layer..."
    docker compose --env-file "$SERVICES_ENV_FILE" -f ./docker-compose-azerothcore-services.yml up -d 2>&1 | grep -v "Found orphan containers"

    # Wait for client data extraction
    print_status "INFO" "Waiting for client data download and extraction (optimized: 8-15 minutes typical)..."
    print_status "INFO" "Press Ctrl+C to exit if needed..."
    wait_for_service "Client Data" 360 "docker logs ac-client-data 2>/dev/null | grep -q 'Game data setup complete'"

    # Wait for worldserver to be healthy
    wait_for_service "World Server" 24 "check_container_health ac-worldserver"

    # Deploy modules if enabled
    if [ "$MODULES_ENABLED" = true ]; then
        print_status "INFO" "Step 3: Deploying modules layer..."

        # Ensure ac-modules is recreated with the correct environment
        # It may have been created earlier by the services layer using services env
        if docker ps -a --format '{{.Names}}' | grep -q '^ac-modules$'; then
            print_status "INFO" "Recreating ac-modules with modules env (removing existing container)"
            docker rm -f ac-modules >/dev/null 2>&1 || true
        fi

        docker compose --env-file "$MODULES_ENV_FILE" -f ./docker-compose-azerothcore-modules.yml up -d 2>&1 | grep -v "Found orphan containers"

        # Wait for modules to be ready
        sleep 5

        STEP_NUMBER=4
    else
        print_status "INFO" "Modules layer skipped (no custom modules configuration found)"
        STEP_NUMBER=3
    fi

    print_status "INFO" "Step $STEP_NUMBER: Deploying tools layer..."
    docker compose --env-file "$TOOLS_ENV_FILE" -f ./docker-compose-azerothcore-tools.yml up -d

    # Wait for tools to be ready
    sleep 10

    print_status "SUCCESS" "Deployment completed!"
}

# Function to perform health checks
perform_health_checks() {
    print_status "HEADER" "CONTAINER HEALTH STATUS"

    # Check all containers
    local containers=("ac-mysql" "ac-backup" "ac-authserver" "ac-worldserver" "ac-phpmyadmin" "ac-keira3")

    # Add modules container if modules are enabled
    if [ "$MODULES_ENABLED" = true ]; then
        containers+=("ac-modules")
    fi

    local container_failures=0

    for container in "${containers[@]}"; do
        # Only check containers that actually exist
        if docker ps -a --format '{{.Names}}' | grep -q "^${container}$"; then
            if ! check_container_health "$container"; then
                # Only count as failure if container is not running, not just missing health check
                if ! docker ps --format '{{.Names}}' | grep -q "^${container}$"; then
                    ((container_failures++))
                fi
            fi
        fi
    done

    print_status "HEADER" "PORT CONNECTIVITY TESTS"

    # Database Layer
    print_status "INFO" "Database Layer:"
    local port_failures=0
    if ! check_port 64306 "MySQL"; then ((port_failures++)); fi

    # Services Layer
    print_status "INFO" "Services Layer:"
    if ! check_port 3784 "Auth Server"; then ((port_failures++)); fi
    if ! check_port 8215 "World Server"; then ((port_failures++)); fi
    if ! check_port 7778 "SOAP API"; then ((port_failures++)); fi

    # Tools Layer
    print_status "INFO" "Tools Layer:"
    if ! check_port 8081 "PHPMyAdmin"; then ((port_failures++)); fi
    if ! check_port 4201 "Keira3"; then ((port_failures++)); fi

    if [ "$QUICK_CHECK" = false ]; then
        print_status "HEADER" "WEB SERVICE HEALTH CHECKS"

        local web_failures=0
        if ! check_web_service "http://localhost:8081/" "PHPMyAdmin" "phpMyAdmin"; then ((web_failures++)); fi
        if ! check_web_service "http://localhost:4201/health" "Keira3" "healthy"; then ((web_failures++)); fi

        print_status "HEADER" "DATABASE CONNECTIVITY TEST"

        # Test database connectivity and verify schemas
        if docker exec ac-mysql mysql -uroot -pazerothcore123 -e "SHOW DATABASES;" 2>/dev/null | grep -q "acore_auth"; then
            print_status "SUCCESS" "Database schemas: verified"
        else
            print_status "ERROR" "Database schemas: verification failed"
            ((web_failures++))
        fi

        # Test realm configuration
        realm_count=$(docker exec ac-mysql mysql -uroot -pazerothcore123 -e "USE acore_auth; SELECT COUNT(*) FROM realmlist;" 2>/dev/null | tail -1)
        if [ "$realm_count" -gt 0 ] 2>/dev/null; then
            print_status "SUCCESS" "Realm configuration: $realm_count realm(s) configured"
        else
            print_status "ERROR" "Realm configuration: no realms found"
            ((web_failures++))
        fi
    fi

    print_status "HEADER" "DEPLOYMENT SUMMARY"

    # Summary
    local total_failures=$((container_failures + port_failures + ${web_failures:-0}))

    if [ $total_failures -eq 0 ]; then
        print_status "SUCCESS" "All services are healthy and operational!"
        print_status "INFO" "Available services:"
        echo "  🌐 PHPMyAdmin:      http://localhost:8081"
        echo "  🛠️  Keira3:         http://localhost:4201"
        echo "  🎮 Game Server:     localhost:8215"
        echo "  🔐 Auth Server:     localhost:3784"
        echo "  🔧 SOAP API:        localhost:7778"
        echo "  🗄️  MySQL:          localhost:64306"
        echo ""
        print_status "INFO" "Default credentials:"
        echo "  🗄️  MySQL:          root / azerothcore123"
        return 0
    else
        print_status "ERROR" "Health check failed with $total_failures issue(s)"
        print_status "INFO" "Check container logs for details: docker logs <container-name>"
        return 1
    fi
}

# Function to show container status
show_container_status() {
    print_status "HEADER" "CONTAINER STATUS OVERVIEW"

    echo -e "${BLUE}Container Name\t\tStatus\t\t\tPorts${NC}"
    echo "=================================================================="
    docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" | grep ac- | while read line; do
        echo "$line"
    done
}

# Main execution
main() {
    print_status "HEADER" "AZEROTHCORE DEPLOYMENT & HEALTH CHECK"

    # Check if docker is available
    if ! command -v docker &> /dev/null; then
        print_status "ERROR" "Docker is not installed or not in PATH"
        exit 1
    fi

    # Check if docker compose is available
    if ! docker compose version &> /dev/null; then
        print_status "ERROR" "Docker Compose is not available"
        exit 1
    fi

    # Run setup if requested
    if [ "$RUN_SETUP" = true ]; then
        print_status "HEADER" "RUNNING SERVER SETUP"
        print_status "INFO" "Starting interactive server configuration..."

        # Change to parent directory to run setup script
        cd "$(dirname "$(pwd)")"

        if [ -f "scripts/setup-server.sh" ]; then
            bash scripts/setup-server.sh
            if [ $? -ne 0 ]; then
                print_status "ERROR" "Server setup failed or was cancelled"
                exit 1
            fi
        else
            print_status "ERROR" "Setup script not found at scripts/setup-server.sh"
            exit 1
        fi

        # Return to scripts directory
        cd scripts
        print_status "SUCCESS" "Server setup completed!"
        echo ""
    fi

    # Deploy the stack unless skipped
    if [ "$SKIP_DEPLOY" = false ]; then
        deploy_stack
    else
        print_status "INFO" "Skipping deployment, running health checks only..."
    fi

    # Show container status
    show_container_status

    # Perform health checks
    if perform_health_checks; then
        print_status "SUCCESS" "🎉 AzerothCore stack is fully operational!"
        exit 0
    else
        print_status "ERROR" "❌ Health check failed - see issues above"
        exit 1
    fi
}

# Run main function
main "$@"
