<# ============================================================
 # Office Translator - Deployment Script (PowerShell / Windows)
 # ============================================================
 # Usage: .\deploy.ps1 <command> [options]
 #
 # Commands:
 #   start     Build and start all services
 #   stop      Stop all services
 #   restart   Restart all services
 #   status    Show services status
 #   logs      Show logs (follow mode)
 #   build     Build/rebuild images
 #   health    Run health checks
 #   backup    Backup PostgreSQL database
 #   clean     Remove all containers, volumes, and images
 #   shell     Open a shell in the backend container
 #   migrate   Run database migrations
 #   help      Show this help message
 #
 # Options:
 #   --env <file>      Use a specific env file (default: .env.docker)
 #   --prod            Use production compose file (docker-compose.yml)
 #   --no-build        Skip build step on start
 #   --rebuild         Force rebuild without cache
 #
 # Examples:
 #   .\deploy.ps1 start                          # Start with defaults (local)
 #   .\deploy.ps1 start --rebuild                # Force rebuild
 #   .\deploy.ps1 start --prod                   # Start production stack
 #   .\deploy.ps1 logs backend                   # Show backend logs
 #   .\deploy.ps1 logs                           # Show all logs
 #   .\deploy.ps1 backup                         # Backup database
 #   .\deploy.ps1 clean                          # Full cleanup
 # ============================================================ #>

param(
    [Parameter(Position = 0)]
    [string]$UserCommand,
    [Parameter(ValueFromRemainingArguments = $true)]
    [string[]]$ExtraArgs
)

$ErrorActionPreference = "Stop"

# ---- Configuration ----
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
Set-Location $ScriptDir

$script:ComposeLocal  = "docker-compose.local.yml"
$script:ComposeProd   = "docker-compose.yml"
$script:EnvFile       = ".env.docker"
$script:ComposeFile   = $script:ComposeLocal
$script:Command       = if ($UserCommand) { $UserCommand } else { "help" }
$script:Service       = ""
$script:NoBuild       = $false
$script:Rebuild       = $false

# ---- Colors ----
function Write-Info   { param([string]$msg) Write-Host "`e[34m[INFO]`e[0m  $msg" }
function Write-OK     { param([string]$msg) Write-Host "`e[32m[OK]`e[0m    $msg" }
function Write-WarnMs { param([string]$msg) Write-Host "`e[33m[WARN]`e[0m  $msg" }
function Write-ErrMsg { param([string]$msg) Write-Host "`e[31m[ERROR]`e[0m $msg" }
function Write-Header { param([string]$msg)
    Write-Host ""
    Write-Host "`e[1;36m========================================`e[0m"
    Write-Host "`e[1;36m  $msg`e[0m"
    Write-Host "`e[1;36m========================================`e[0m"
}

# ---- Docker Compose wrapper ----
function Invoke-Dc {
    param([Parameter(Mandatory)][string[]]$DcArgs)
    & docker compose -f $script:ComposeFile --env-file $script:EnvFile @DcArgs
}

# ---- Parse remaining arguments ----
$i = 0
while ($i -lt $ExtraArgs.Count) {
    $arg = $ExtraArgs[$i]
    switch ($arg) {
        "--env" {
            $script:EnvFile = $ExtraArgs[$i + 1]
            $i += 2
        }
        "--prod" {
            $script:ComposeFile = $script:ComposeProd
            $i++
        }
        "--no-build" {
            $script:NoBuild = $true
            $i++
        }
        "--rebuild" {
            $script:Rebuild = $true
            $i++
        }
        { $_ -in "backend", "frontend", "postgres", "redis", "nginx", "ollama" } {
            $script:Service = $_
            $i++
        }
        default { $i++ }
    }
}

# ---- Prerequisite Checks ----
function Test-Prerequisites {
    if (-not (Get-Command docker -ErrorAction SilentlyContinue)) {
        Write-ErrMsg "Docker is not installed. Install it from https://docs.docker.com/desktop/install/windows-install/"
        exit 1
    }

    try {
        $null = docker info 2>&1
    } catch {
        Write-ErrMsg "Docker daemon is not running. Start Docker Desktop."
        exit 1
    }

    try {
        $null = docker compose version 2>&1
    } catch {
        Write-ErrMsg "Docker Compose V2 is not available. Update Docker Desktop."
        exit 1
    }

    if (-not (Test-Path $script:EnvFile)) {
        Write-ErrMsg "Environment file '$($script:EnvFile)' not found."
        if ($script:EnvFile -eq ".env.docker") {
            Write-Info "Creating .env.docker from default settings..."
            $envContent = @"
ENV=production
LOG_LEVEL=INFO
LOG_FORMAT=console
ENABLE_REQUEST_LOGGING=true
TRANSLATION_SERVICE=google
GOOGLE_TRANSLATE_ENABLED=true
DEEPL_ENABLED=false
OPENAI_ENABLED=false
OLLAMA_ENABLED=false
OPENROUTER_ENABLED=false
PROVIDER_FALLBACK_CHAIN=google,deepl,openai,ollama,openrouter
FALLBACK_CHAIN_CLASSIC=google,deepl
FALLBACK_CHAIN_LLM=ollama,openai
MAX_FILE_SIZE_MB=50
MAX_REQUEST_SIZE_MB=100
REQUEST_TIMEOUT_SECONDS=300
RATE_LIMIT_ENABLED=true
RATE_LIMIT_PER_MINUTE=30
RATE_LIMIT_PER_HOUR=200
TRANSLATIONS_PER_MINUTE=10
TRANSLATIONS_PER_HOUR=50
MAX_CONCURRENT_TRANSLATIONS=5
CLEANUP_ENABLED=true
CLEANUP_INTERVAL_MINUTES=5
FILE_TTL_MINUTES=60
INPUT_FILE_TTL_MINUTES=30
OUTPUT_FILE_TTL_MINUTES=120
DISK_WARNING_THRESHOLD_GB=5.0
DISK_CRITICAL_THRESHOLD_GB=1.0
ENABLE_HSTS=false
CORS_ORIGINS=http://localhost,http://localhost:3000,http://localhost:8000
MAX_MEMORY_PERCENT=80
POSTGRES_USER=translate
POSTGRES_PASSWORD=translate_local_2026
POSTGRES_DB=translate_db
POSTGRES_HOST=postgres
POSTGRES_PORT=5432
DATABASE_ECHO=false
ADMIN_USERNAME=admin
ADMIN_PASSWORD=admin123
ADMIN_TOKEN_SECRET=docker_local_admin_token_secret_2026_abc123xyz
JWT_SECRET_KEY=docker_local_jwt_secret_key_2026_x7k9m3p5q8r2s4t6
FRONTEND_URL=http://localhost
NEXT_PUBLIC_API_URL=
BACKEND_URL=http://backend:8000
HTTP_PORT=80
"@
            Set-Content -Path ".env.docker" -Value $envContent -Encoding UTF8
            Write-OK "Created .env.docker with default local settings"
        } else {
            exit 1
        }
    }

    $portsToCheck = @(80, 3000, 5432, 6379)
    foreach ($port in $portsToCheck) {
        $listening = netstat -ano 2>$null | Select-String ":$port\s" | Select-String "LISTENING"
        if ($listening) {
            Write-WarnMs "Port $port is already in use. This may cause conflicts."
        }
    }

    Write-OK "Prerequisites OK (Docker + Compose + $($script:EnvFile))"
}

# ---- Command Functions ----

function Invoke-Start {
    Write-Header "Office Translator - Starting"
    Test-Prerequisites

    $dcArgs = @()
    if ($script:Service) { $dcArgs += $script:Service }

    if ($script:Rebuild) {
        Write-Info "Building images (no cache)..."
        Invoke-Dc -DcArgs (@("build", "--no-cache") + $dcArgs)
    } elseif (-not $script:NoBuild) {
        Write-Info "Building images..."
        Invoke-Dc -DcArgs (@("build") + $dcArgs)
    } else {
        Write-Info "Skipping build (--no-build)"
    }

    Write-Info "Starting services..."
    $upArgs = @("up", "-d")
    if ($script:Service) { $upArgs += $script:Service }
    Invoke-Dc -DcArgs $upArgs

    Write-Info "Waiting for services to be ready..."
    $maxWait = 120
    $elapsed = 0
    while ($elapsed -lt $maxWait) {
        $backendOk = $false
        $frontendOk = $false

        try { $null = Invoke-WebRequest -Uri "http://localhost:8000/health" -UseBasicParsing -TimeoutSec 2 -ErrorAction Stop; $backendOk = $true } catch {}
        try { $null = Invoke-WebRequest -Uri "http://localhost:3000" -UseBasicParsing -TimeoutSec 2 -ErrorAction Stop; $frontendOk = $true } catch {}

        if ($backendOk -and $frontendOk) { break }

        Start-Sleep -Seconds 3
        $elapsed += 3
        Write-Host -NoNewline "`r  Waiting... ($($elapsed)s/$($maxWait)s) backend=$backendOk frontend=$frontendOk"
    }
    Write-Host ""

    Write-Host ""
    Invoke-Health

    Write-Host ""
    Invoke-Dc -DcArgs @("ps")

    Write-Host ""
    Write-OK "Application is running!"
    Write-Host ""
    Write-Info "Access points:"
    Write-Host "  Frontend:  http://localhost"
    Write-Host "  Backend:   http://localhost:8000"
    Write-Host "  API docs:  http://localhost:8000/docs"
    Write-Host "  Admin:     http://localhost/admin (admin / admin123)"
    Write-Host "  Health:    http://localhost/health"
    Write-Host ""
    Write-Info "Useful commands:"
    Write-Host "  .\deploy.ps1 logs          Follow logs"
    Write-Host "  .\deploy.ps1 status        Check status"
    Write-Host "  .\deploy.ps1 stop          Stop all"
}

function Invoke-Stop {
    Write-Header "Stopping Services"
    $downArgs = @("down", "--remove-orphans")
    if ($script:Service) { $downArgs += $script:Service }
    Invoke-Dc -DcArgs $downArgs
    Write-OK "Services stopped"
}

function Invoke-Restart {
    Write-Header "Restarting Services"
    Write-Info "Restarting..."
    $restartArgs = @("restart")
    if ($script:Service) { $restartArgs += $script:Service }
    Invoke-Dc -DcArgs $restartArgs
    Write-OK "Services restarted"
    Start-Sleep -Seconds 5
    Invoke-Health
}

function Invoke-Status {
    Write-Header "Service Status"
    Invoke-Dc -DcArgs @("ps")
    Write-Host ""

    Write-Info "Health checks:"

    $backendCode = "000"
    $frontendCode = "000"
    $nginxCode = "000"

    try { $resp = Invoke-WebRequest -Uri "http://localhost:8000/health" -UseBasicParsing -TimeoutSec 5 -ErrorAction Stop; $backendCode = [string]$resp.StatusCode } catch {}
    try { $resp = Invoke-WebRequest -Uri "http://localhost:3000" -UseBasicParsing -TimeoutSec 5 -ErrorAction Stop; $frontendCode = [string]$resp.StatusCode } catch {}
    try { $resp = Invoke-WebRequest -Uri "http://localhost/health" -UseBasicParsing -TimeoutSec 5 -ErrorAction Stop; $nginxCode = [string]$resp.StatusCode } catch {}

    if ($backendCode -eq "200")  { Write-OK "Backend  (HTTP $backendCode)" } else { Write-ErrMsg "Backend  (HTTP $backendCode)" }
    if ($frontendCode -eq "200") { Write-OK "Frontend (HTTP $frontendCode)" } else { Write-ErrMsg "Frontend (HTTP $frontendCode)" }
    if ($nginxCode -eq "200")    { Write-OK "Nginx    (HTTP $nginxCode)" } else { Write-ErrMsg "Nginx    (HTTP $nginxCode)" }
}

function Invoke-Logs {
    $logArgs = @("logs", "-f", "--tail")
    if ($script:Service) {
        $logArgs += @("100", $script:Service)
    } else {
        $logArgs += "50"
    }
    Invoke-Dc -DcArgs $logArgs
}

function Invoke-BuildCmd {
    Write-Header "Building Images"
    Test-Prerequisites

    $buildArgs = @("build")
    if ($script:Rebuild) {
        $buildArgs += "--no-cache"
        Write-Info "Building without cache..."
    } else {
        Write-Info "Building..."
    }
    if ($script:Service) { $buildArgs += $script:Service }
    Invoke-Dc -DcArgs $buildArgs
    Write-OK "Build complete"
}

function Invoke-Health {
    Write-Info "Running health checks..."

    $backendResponse = '{"status":"unreachable"}'
    try {
        $resp = Invoke-WebRequest -Uri "http://localhost:8000/health" -UseBasicParsing -TimeoutSec 5 -ErrorAction Stop
        $backendResponse = $resp.Content
    } catch {}

    try {
        $parsed = $backendResponse | ConvertFrom-Json
        if ($parsed.status -eq "healthy") {
            Write-OK "Backend: healthy"
        } else {
            $bCode = "000"
            try { $r = Invoke-WebRequest -Uri "http://localhost:8000/health" -UseBasicParsing -TimeoutSec 5 -ErrorAction Stop; $bCode = [string]$r.StatusCode } catch {}
            Write-ErrMsg "Backend: unhealthy (HTTP $bCode)"
        }
    } catch {
        Write-ErrMsg "Backend: unhealthy"
    }

    try { $null = Invoke-WebRequest -Uri "http://localhost:3000" -UseBasicParsing -TimeoutSec 5 -ErrorAction Stop; Write-OK "Frontend: responding" } catch { Write-ErrMsg "Frontend: not responding" }
    try { $null = Invoke-WebRequest -Uri "http://localhost/health" -UseBasicParsing -TimeoutSec 5 -ErrorAction Stop; Write-OK "Nginx: proxying correctly" } catch { Write-WarnMs "Nginx: not reachable on port 80" }

    try {
        Invoke-Dc -DcArgs @("exec", "-T", "postgres", "pg_isready", "-U", "translate", "-d", "translate_db") 2>$null | Out-Null
        if ($LASTEXITCODE -eq 0) { Write-OK "PostgreSQL: ready" } else { Write-ErrMsg "PostgreSQL: not ready" }
    } catch { Write-ErrMsg "PostgreSQL: not ready" }

    try {
        $result = Invoke-Dc -DcArgs @("exec", "-T", "redis", "redis-cli", "ping") 2>$null
        if ($result -match "PONG") { Write-OK "Redis: ready (PONG)" } else { Write-ErrMsg "Redis: not ready" }
    } catch { Write-ErrMsg "Redis: not ready" }
}

function Invoke-Backup {
    Write-Header "Database Backup"
    $timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
    $backupDir = "backups"
    if (-not (Test-Path $backupDir)) {
        New-Item -ItemType Directory -Path $backupDir | Out-Null
    }

    $backupFile = "$backupDir/translate_db_$timestamp.sql"

    Write-Info "Backing up PostgreSQL to $backupFile..."
    Invoke-Dc -DcArgs @("exec", "-T", "postgres", "pg_dump", "-U", "translate", "translate_db") | Out-File -FilePath $backupFile -Encoding UTF8

    $size = (Get-Item $backupFile).Length
    $sizeFormatted = "{0:N2} KB" -f ($size / 1KB)
    Write-OK "Backup complete: $backupFile ($sizeFormatted)"
}

function Invoke-Clean {
    Write-Header "Full Cleanup"
    Write-WarnMs "This will remove all containers, volumes, and images for this project."
    $reply = Read-Host "Are you sure? [y/N]"

    if ($reply -match "^[Yy]$") {
        Write-Info "Stopping and removing containers..."
        Invoke-Dc -DcArgs @("down", "-v", "--rmi", "local", "--remove-orphans")

        Write-Info "Pruning dangling resources..."
        & docker system prune -f

        Write-OK "Cleanup complete"
    } else {
        Write-Info "Cancelled"
    }
}

function Invoke-Shell {
    $target = if ($script:Service) { $script:Service } else { "backend" }
    Write-Info "Opening shell in $target container..."
    try {
        Invoke-Dc -DcArgs @("exec", $target, "/bin/bash")
    } catch {
        Invoke-Dc -DcArgs @("exec", $target, "/bin/sh")
    }
}

function Invoke-Migrate {
    Write-Header "Running Database Migrations"
    Write-Info "Running alembic upgrade head..."
    Invoke-Dc -DcArgs @("exec", "backend", "alembic", "upgrade", "head")
    Write-OK "Migrations complete"
}

function Show-Help {
    Write-Host ""
    Write-Host "`e[1mOffice Translator - Deployment Script (PowerShell)`e[0m"
    Write-Host ""
    Write-Host "Usage: .\deploy.ps1 <command> [options]"
    Write-Host ""
    Write-Host "`e[1mCommands:`e[0m"
    Write-Host "  start       Build and start all services"
    Write-Host "  stop        Stop all services"
    Write-Host "  restart     Restart all services"
    Write-Host "  status      Show services status"
    Write-Host "  logs [svc]  Show logs (optional: backend, frontend, postgres, redis, nginx)"
    Write-Host "  build       Build/rebuild Docker images"
    Write-Host "  health      Run health checks on all services"
    Write-Host "  backup      Backup PostgreSQL database"
    Write-Host "  clean       Remove all containers, volumes, and images"
    Write-Host "  shell [svc] Open shell in a container (default: backend)"
    Write-Host "  migrate     Run database migrations"
    Write-Host "  help        Show this help message"
    Write-Host ""
    Write-Host "`e[1mOptions:`e[0m"
    Write-Host "  --env <file>    Use a specific env file (default: .env.docker)"
    Write-Host "  --prod          Use production compose file"
    Write-Host "  --no-build      Skip build step"
    Write-Host "  --rebuild       Force rebuild without Docker cache"
    Write-Host ""
    Write-Host "`e[1mExamples:`e[0m"
    Write-Host "  .\deploy.ps1 start"
    Write-Host "  .\deploy.ps1 start --rebuild"
    Write-Host "  .\deploy.ps1 start --prod --env .env.production"
    Write-Host "  .\deploy.ps1 logs backend"
    Write-Host "  .\deploy.ps1 shell postgres"
    Write-Host "  .\deploy.ps1 backup"
    Write-Host ""
}

# ---- Main ----

switch ($script:Command) {
    "start"    { Invoke-Start }
    "stop"     { Invoke-Stop }
    "restart"  { Invoke-Restart }
    "status"   { Invoke-Status }
    "logs"     { Invoke-Logs }
    "build"    { Invoke-BuildCmd }
    "health"   { Invoke-Health }
    "backup"   { Invoke-Backup }
    "clean"    { Invoke-Clean }
    "shell"    { Invoke-Shell }
    "migrate"  { Invoke-Migrate }
    { $_ -in "help", "--help", "-h" } { Show-Help }
    default {
        Write-ErrMsg "Unknown command: $($script:Command)"
        Show-Help
        exit 1
    }
}
