#!/bin/bash

# ThrillWiki Server Start Script
# Stops any running servers, clears caches, runs migrations, and starts both servers
# Works whether servers are currently running or not
# Usage: ./start-servers.sh

set -e  # Exit on any error

# Global variables for process management
BACKEND_PID=""
FRONTEND_PID=""
CLEANUP_PERFORMED=false

# 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 directory and project root
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
BACKEND_DIR="$PROJECT_ROOT/backend"
FRONTEND_DIR="$PROJECT_ROOT/frontend"

# Function to print colored output
print_status() {
    echo -e "${BLUE}[INFO]${NC} $1"
}

print_success() {
    echo -e "${GREEN}[SUCCESS]${NC} $1"
}

print_warning() {
    echo -e "${YELLOW}[WARNING]${NC} $1"
}

print_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

# Function for graceful shutdown
graceful_shutdown() {
    if [ "$CLEANUP_PERFORMED" = true ]; then
        return 0
    fi
    
    CLEANUP_PERFORMED=true
    
    print_warning "Received shutdown signal - performing graceful shutdown..."
    
    # Disable further signal handling to prevent recursive calls
    trap - INT TERM
    
    # Kill backend server if running
    if [ -n "$BACKEND_PID" ] && kill -0 "$BACKEND_PID" 2>/dev/null; then
        print_status "Stopping backend server (PID: $BACKEND_PID)..."
        kill -TERM "$BACKEND_PID" 2>/dev/null || true
        
        # Wait up to 10 seconds for graceful shutdown
        local count=0
        while [ $count -lt 10 ] && kill -0 "$BACKEND_PID" 2>/dev/null; do
            sleep 1
            count=$((count + 1))
        done
        
        # Force kill if still running
        if kill -0 "$BACKEND_PID" 2>/dev/null; then
            print_warning "Force killing backend server..."
            kill -KILL "$BACKEND_PID" 2>/dev/null || true
        fi
        print_success "Backend server stopped"
    else
        print_status "Backend server not running or already stopped"
    fi
    
    # Kill frontend server if running
    if [ -n "$FRONTEND_PID" ] && kill -0 "$FRONTEND_PID" 2>/dev/null; then
        print_status "Stopping frontend server (PID: $FRONTEND_PID)..."
        kill -TERM "$FRONTEND_PID" 2>/dev/null || true
        
        # Wait up to 10 seconds for graceful shutdown
        local count=0
        while [ $count -lt 10 ] && kill -0 "$FRONTEND_PID" 2>/dev/null; do
            sleep 1
            count=$((count + 1))
        done
        
        # Force kill if still running
        if kill -0 "$FRONTEND_PID" 2>/dev/null; then
            print_warning "Force killing frontend server..."
            kill -KILL "$FRONTEND_PID" 2>/dev/null || true
        fi
        print_success "Frontend server stopped"
    else
        print_status "Frontend server not running or already stopped"
    fi
    
    # Clear PID files if they exist
    if [ -f "$PROJECT_ROOT/shared/logs/backend.pid" ]; then
        rm -f "$PROJECT_ROOT/shared/logs/backend.pid"
    fi
    if [ -f "$PROJECT_ROOT/shared/logs/frontend.pid" ]; then
        rm -f "$PROJECT_ROOT/shared/logs/frontend.pid"
    fi
    
    print_success "Graceful shutdown completed"
    exit 0
}

# Function to kill processes by pattern
kill_processes() {
    local pattern="$1"
    local description="$2"
    
    print_status "Checking for $description processes..."
    
    # Find and kill processes
    local pids=$(pgrep -f "$pattern" 2>/dev/null || true)
    
    if [ -n "$pids" ]; then
        print_status "Found $description processes, stopping them..."
        echo "$pids" | xargs kill -TERM 2>/dev/null || true
        sleep 2
        
        # Force kill if still running
        local remaining_pids=$(pgrep -f "$pattern" 2>/dev/null || true)
        if [ -n "$remaining_pids" ]; then
            print_warning "Force killing remaining $description processes..."
            echo "$remaining_pids" | xargs kill -KILL 2>/dev/null || true
        fi
        
        print_success "$description processes stopped"
    else
        print_status "No $description processes found (this is fine)"
    fi
}

# Function to clear Django cache
clear_django_cache() {
    print_status "Clearing Django cache..."
    
    cd "$BACKEND_DIR"
    
    # Clear Django cache
    if command -v uv >/dev/null 2>&1; then
        if ! uv run manage.py clear_cache 2>clear_cache_error.log; then
            print_error "Django clear_cache command failed:"
            cat clear_cache_error.log
            rm -f clear_cache_error.log
            exit 1
        else
            rm -f clear_cache_error.log
        fi
    else
        print_error "uv not found! Please install uv first."
        exit 1
    fi
    
    # Remove Python cache files
    find . -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true
    find . -name "*.pyc" -delete 2>/dev/null || true
    find . -name "*.pyo" -delete 2>/dev/null || true
    
    print_success "Django cache cleared"
}

# Function to clear frontend cache
clear_frontend_cache() {
    print_status "Clearing frontend cache..."
    
    cd "$FRONTEND_DIR"
    
    # Remove node_modules/.cache if it exists
    if [ -d "node_modules/.cache" ]; then
        rm -rf node_modules/.cache
        print_status "Removed node_modules/.cache"
    fi
    
    # Remove .nuxt cache if it exists (for Nuxt projects)
    if [ -d ".nuxt" ]; then
        rm -rf .nuxt
        print_status "Removed .nuxt cache"
    fi
    
    # Remove dist/build directories
    if [ -d "dist" ]; then
        rm -rf dist
        print_status "Removed dist directory"
    fi
    
    if [ -d "build" ]; then
        rm -rf build
        print_status "Removed build directory"
    fi
    
    # Clear pnpm cache
    if command -v pnpm >/dev/null 2>&1; then
        pnpm store prune 2>/dev/null || print_warning "Could not prune pnpm store"
    else
        print_error "pnpm not found! Please install pnpm first."
        exit 1
    fi
    
    print_success "Frontend cache cleared"
}

# Function to run Django migrations
run_migrations() {
    print_status "Running Django migrations..."
    
    cd "$BACKEND_DIR"
    
    # Check for pending migrations
    if uv run python manage.py showmigrations --plan | grep -q "\[ \]"; then
        print_status "Pending migrations found, applying..."
        uv run python manage.py migrate
        print_success "Migrations applied successfully"
    else
        print_status "No pending migrations found"
    fi
    
    # Run any custom management commands if needed
    # uv run python manage.py collectstatic --noinput --clear 2>/dev/null || print_warning "collectstatic failed or not needed"
}

# Function to start backend server
start_backend() {
    print_status "Starting Django backend server with runserver_plus (verbose output)..."
    
    cd "$BACKEND_DIR"
    
    # Start Django development server with runserver_plus for enhanced features and verbose output
    print_status "Running: uv run python manage.py runserver_plus 8000 --verbosity=2"
    uv run python manage.py runserver_plus 8000 --verbosity=2 &
    BACKEND_PID=$!
    
    # Make sure the background process can receive signals
    disown -h "$BACKEND_PID" 2>/dev/null || true
    
    # Wait a moment and check if it started successfully
    sleep 3
    if kill -0 $BACKEND_PID 2>/dev/null; then
        print_success "Backend server started (PID: $BACKEND_PID)"
        echo $BACKEND_PID > ../shared/logs/backend.pid
    else
        print_error "Failed to start backend server"
        return 1
    fi
}

# Function to start frontend server
start_frontend() {
    print_status "Starting frontend server with verbose output..."
    
    cd "$FRONTEND_DIR"
    
    # Install dependencies if node_modules doesn't exist or package.json is newer
    if [ ! -d "node_modules" ] || [ "package.json" -nt "node_modules" ]; then
        print_status "Installing/updating frontend dependencies..."
        pnpm install
    fi
    
    # Start frontend development server using Vite with explicit port, auto-open, and verbose output
    # --port 5173: Use standard Vite port
    # --open: Automatically open browser when ready
    # --host localhost: Ensure it binds to localhost
    # --debug: Enable debug logging
    print_status "Starting Vite development server with verbose output and auto-browser opening..."
    print_status "Running: pnpm vite --port 5173 --open --host localhost --debug"
    pnpm vite --port 5173 --open --host localhost --debug &
    FRONTEND_PID=$!
    
    # Make sure the background process can receive signals
    disown -h "$FRONTEND_PID" 2>/dev/null || true
    
    # Wait a moment and check if it started successfully
    sleep 3
    if kill -0 $FRONTEND_PID 2>/dev/null; then
        print_success "Frontend server started (PID: $FRONTEND_PID) - browser should open automatically"
        echo $FRONTEND_PID > ../shared/logs/frontend.pid
    else
        print_error "Failed to start frontend server"
        return 1
    fi
}

# Function to detect operating system
detect_os() {
    case "$(uname -s)" in
        Darwin*)    echo "macos";;
        Linux*)     echo "linux";;
        *)          echo "unknown";;
    esac
}

# Function to open browser on the appropriate OS
open_browser() {
    local url="$1"
    local os=$(detect_os)
    
    print_status "Opening browser to $url..."
    
    case "$os" in
        "macos")
            if command -v open >/dev/null 2>&1; then
                open "$url" 2>/dev/null || print_warning "Failed to open browser automatically"
            else
                print_warning "Cannot open browser: 'open' command not available"
            fi
            ;;
        "linux")
            if command -v xdg-open >/dev/null 2>&1; then
                xdg-open "$url" 2>/dev/null || print_warning "Failed to open browser automatically"
            else
                print_warning "Cannot open browser: 'xdg-open' command not available"
            fi
            ;;
        *)
            print_warning "Cannot open browser automatically: Unsupported operating system"
            ;;
    esac
}

# Function to verify frontend is responding (simplified since port is known)
verify_frontend_ready() {
    local frontend_url="http://localhost:5173"
    local max_checks=15
    local check=0
    
    print_status "Verifying frontend server is responding at $frontend_url..."
    
    while [ $check -lt $max_checks ]; do
        local response_code=$(curl -s -o /dev/null -w "%{http_code}" "$frontend_url" 2>/dev/null)
        if [ "$response_code" = "200" ] || [ "$response_code" = "301" ] || [ "$response_code" = "302" ] || [ "$response_code" = "404" ]; then
            print_success "Frontend server is responding (HTTP $response_code)"
            return 0
        fi
        
        if [ $((check % 3)) -eq 0 ]; then
            print_status "Waiting for frontend to respond... (attempt $((check + 1))/$max_checks)"
        fi
        sleep 2
        check=$((check + 1))
    done
    
    print_warning "Frontend may still be starting up"
    return 1
}

# Function to verify servers are responding
verify_servers_ready() {
    print_status "Verifying both servers are responding..."
    
    # Check backend
    local backend_ready=false
    local frontend_ready=false
    local max_checks=10
    local check=0
    
    while [ $check -lt $max_checks ]; do
        # Check backend
        if [ "$backend_ready" = false ]; then
            local backend_response=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:8000" 2>/dev/null)
            if [ "$backend_response" = "200" ] || [ "$backend_response" = "301" ] || [ "$backend_response" = "302" ] || [ "$backend_response" = "404" ]; then
                print_success "Backend server is responding (HTTP $backend_response)"
                backend_ready=true
            fi
        fi
        
        # Check frontend
        if [ "$frontend_ready" = false ]; then
            local frontend_response=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:5173" 2>/dev/null)
            if [ "$frontend_response" = "200" ] || [ "$frontend_response" = "301" ] || [ "$frontend_response" = "302" ] || [ "$frontend_response" = "404" ]; then
                print_success "Frontend server is responding (HTTP $frontend_response)"
                frontend_ready=true
            fi
        fi
        
        # Both ready?
        if [ "$backend_ready" = true ] && [ "$frontend_ready" = true ]; then
            print_success "Both servers are responding!"
            return 0
        fi
        
        sleep 2
        check=$((check + 1))
    done
    
    # Show status of what's working
    if [ "$backend_ready" = true ]; then
        print_success "Backend is ready at http://localhost:8000"
    else
        print_warning "Backend may still be starting up"
    fi
    
    if [ "$frontend_ready" = true ]; then
        print_success "Frontend is ready at http://localhost:5173"
    else
        print_warning "Frontend may still be starting up"
    fi
}

# Function to create logs directory if it doesn't exist
ensure_logs_dir() {
    local logs_dir="$PROJECT_ROOT/shared/logs"
    if [ ! -d "$logs_dir" ]; then
        mkdir -p "$logs_dir"
        print_status "Created logs directory: $logs_dir"
    fi
}

# Function to validate project structure
validate_project() {
    if [ ! -d "$BACKEND_DIR" ]; then
        print_error "Backend directory not found: $BACKEND_DIR"
        exit 1
    fi
    
    if [ ! -d "$FRONTEND_DIR" ]; then
        print_error "Frontend directory not found: $FRONTEND_DIR"
        exit 1
    fi
    
    if [ ! -f "$BACKEND_DIR/manage.py" ]; then
        print_error "Django manage.py not found in: $BACKEND_DIR"
        exit 1
    fi
    
    if [ ! -f "$FRONTEND_DIR/package.json" ]; then
        print_error "Frontend package.json not found in: $FRONTEND_DIR"
        exit 1
    fi
}

# Function to kill processes using specific ports
kill_port_processes() {
    local port="$1"
    local description="$2"
    
    print_status "Checking for processes using port $port ($description)..."
    
    # Find processes using the specific port
    local pids=$(lsof -ti :$port 2>/dev/null || true)
    
    if [ -n "$pids" ]; then
        print_warning "Found processes using port $port, killing them..."
        echo "$pids" | xargs kill -TERM 2>/dev/null || true
        sleep 2
        
        # Force kill if still running
        local remaining_pids=$(lsof -ti :$port 2>/dev/null || true)
        if [ -n "$remaining_pids" ]; then
            print_warning "Force killing remaining processes on port $port..."
            echo "$remaining_pids" | xargs kill -KILL 2>/dev/null || true
        fi
        
        print_success "Port $port cleared"
    else
        print_status "Port $port is available"
    fi
}

# Function to check and clear required ports
check_and_clear_ports() {
    print_status "Checking and clearing required ports..."
    
    # Kill processes using our specific ports
    kill_port_processes 8000 "Django backend"
    kill_port_processes 5173 "Frontend Vite"
}

# Main execution function
main() {
    print_status "ThrillWiki Server Start Script Starting..."
    print_status "This script works whether servers are currently running or not."
    print_status "Project root: $PROJECT_ROOT"
    
    # Set up signal traps EARLY - before any long-running operations
    print_status "Setting up signal handlers for graceful shutdown..."
    trap 'graceful_shutdown' INT TERM
    
    # Validate project structure
    validate_project
    
    # Ensure logs directory exists
    ensure_logs_dir
    
    # Check and clear ports
    check_and_clear_ports
    
    # Kill existing server processes (if any)
    print_status "=== Stopping Any Running Servers ==="
    print_status "Note: It's perfectly fine if no servers are currently running"
    kill_processes "manage.py runserver" "Django backend"
    kill_processes "pnpm.*dev\|npm.*dev\|yarn.*dev\|node.*dev" "Frontend development"
    kill_processes "uvicorn\|gunicorn" "Python web servers"
    
    # Clear caches
    print_status "=== Clearing Caches ==="
    clear_django_cache
    clear_frontend_cache
    
    # Run migrations
    print_status "=== Running Migrations ==="
    run_migrations
    
    # Start servers
    print_status "=== Starting Servers ==="
    
    # Start backend first
    if start_backend; then
        print_success "Backend server is running"
    else
        print_error "Failed to start backend server"
        exit 1
    fi
    
    # Start frontend
    if start_frontend; then
        print_success "Frontend server is running"
    else
        print_error "Failed to start frontend server"
        print_status "Backend server is still running"
        exit 1
    fi
    
    # Verify servers are responding
    print_status "=== Verifying Servers ==="
    verify_servers_ready
    
    # Final status
    print_status "=== Server Status ==="
    print_success "✅ Backend server: http://localhost:8000 (Django with runserver_plus)"
    print_success "✅ Frontend server: http://localhost:5173 (Vite with verbose output)"
    print_status "🌐 Browser should have opened automatically via Vite --open"
    print_status "🔧 To stop servers, use: kill \$(cat $PROJECT_ROOT/shared/logs/backend.pid) \$(cat $PROJECT_ROOT/shared/logs/frontend.pid)"
    print_status "📋 Both servers are running with verbose output directly in your terminal"
    
    print_success "🚀 All servers started successfully with full verbose output!"
    
    # Keep the script running and wait for signals
    wait_for_servers
}

# Wait for servers function to keep script running and handle signals
wait_for_servers() {
    print_status "🚀 Servers are running! Press Ctrl+C for graceful shutdown."
    print_status "📋 Backend: http://localhost:8000 | Frontend: http://localhost:5173"
    
    # Keep the script alive and wait for signals
    while [ "$CLEANUP_PERFORMED" != true ]; do
        # Check if both servers are still running
        if [ -n "$BACKEND_PID" ] && ! kill -0 "$BACKEND_PID" 2>/dev/null; then
            print_error "Backend server has stopped unexpectedly"
            graceful_shutdown
            break
        fi
        
        if [ -n "$FRONTEND_PID" ] && ! kill -0 "$FRONTEND_PID" 2>/dev/null; then
            print_error "Frontend server has stopped unexpectedly"
            graceful_shutdown
            break
        fi
        
        # Use shorter sleep and check for signals more frequently
        sleep 1
    done
}

# Run main function (no traps set up initially)
main "$@"