<#
.SYNOPSIS
    Edu start all application services script
.DESCRIPTION
    Starts 10 application services + 1 frontend (teacher-portal)
    Each service runs in a separate terminal window for log visibility
    Automatically injects Python service env vars (CLICKHOUSE/KAFKA/OTEL)
    Prerequisite: infrastructure containers (MySQL/Redis/Kafka/ClickHouse etc) must be running
.PARAMETER SkipInfraCheck
    Skip infrastructure health check (use when infra is known to be running)
.EXAMPLE
    .\scripts\start-all.ps1
    .\scripts\start-all.ps1 -SkipInfraCheck
#>
param(
    [switch]$SkipInfraCheck,
    [switch]$Force
)

$ErrorActionPreference = "Stop"
$ProjectRoot = Split-Path -Parent $PSScriptRoot

Write-Host "========================================" -ForegroundColor Cyan
Write-Host "  Edu Start All Services" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
Write-Host ""

# ===== 1. Infrastructure health check =====
if (-not $SkipInfraCheck) {
    Write-Host "[1/6] Checking infrastructure health..." -ForegroundColor Yellow
    $infraServices = @(
        @{Name="MySQL";       Container="edu-mysql"},
        @{Name="Redis";       Container="edu-redis"},
        @{Name="Kafka";       Container="edu-kafka"},
        @{Name="ClickHouse";  Container="edu-clickhouse"},
        @{Name="Debezium";    Container="edu-debezium"},
        @{Name="Jaeger";      Container="edu-jaeger"}
    )
    $allHealthy = $true
    $prevEAP = $ErrorActionPreference
    $ErrorActionPreference = "Continue"
    foreach ($svc in $infraServices) {
        $running = docker inspect -f '{{.State.Running}}' $svc.Container 2>$null
        if ($running -ne "true") {
            Write-Host "  [FAIL] $($svc.Name) not running" -ForegroundColor Red
            $allHealthy = $false
            continue
        }
        # 条件模板：Health 不存在时返回空字符串，不报错
        $health = docker inspect -f '{{if .State.Health}}{{.State.Health.Status}}{{end}}' $svc.Container 2>$null
        if ($health -eq "healthy") {
            Write-Host "  [OK] $($svc.Name) ($($svc.Container))" -ForegroundColor Green
        } else {
            Write-Host "  [WARN] $($svc.Name) running (no healthcheck)" -ForegroundColor Yellow
        }
    }
    $ErrorActionPreference = $prevEAP
    if (-not $allHealthy) {
        Write-Host ""
        Write-Host "Infrastructure not ready. Start it first:" -ForegroundColor Red
        Write-Host "  docker compose -f infra/docker-compose.yml --profile p6 --profile observability up -d" -ForegroundColor White
        exit 1
    }
    Write-Host ""
}

# ===== 2. Environment variables =====
Write-Host "[2/6] Preparing environment variables..." -ForegroundColor Yellow

$env:DEV_MODE = "true"
$env:OTEL_EXPORTER_OTLP_ENDPOINT = "http://localhost:4318"
$env:DATABASE_URL = "mysql://edu:changeme@localhost:3306/next_edu_cloud"
$env:REDIS_URL = "redis://localhost:6379"
$env:JWT_SECRET = "p1-dev-secret-change-in-production"
$env:KAFKA_BROKERS = "localhost:9092"

$pyEnv = @{
    CLICKHOUSE_HOST     = "localhost"
    CLICKHOUSE_PORT     = "8123"
    CLICKHOUSE_USER     = "default"
    CLICKHOUSE_PASSWORD = "clickhouse"
    CLICKHOUSE_DATABASE = "edu_analytics"
    KAFKA_BROKERS       = "localhost:9092"
    OTEL_ENDPOINT       = "http://localhost:4318"
    DEV_MODE            = "true"
}

Write-Host "  DEV_MODE=true (dev-token bypass)" -ForegroundColor Green
Write-Host "  OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318" -ForegroundColor Green
Write-Host ""

# ===== 3. Port conflict check =====
Write-Host "[3/6] Checking port conflicts..." -ForegroundColor Yellow

$portMap = @{
    3001="classes"; 3002="iam"; 3003="teacher-bff"; 3004="core-edu"
    3005="content"; 3006="data-ana"; 3007="msg"; 3008="ai"
    8080="api-gateway"; 8081="push-gateway"; 3000="teacher-portal"
}

$conflicts = @()
foreach ($port in $portMap.Keys | Sort-Object) {
    $conn = Get-NetTCPConnection -LocalPort $port -State Listen -ErrorAction SilentlyContinue
    if ($conn) {
        $svcName = $portMap[$port]
        $procId = $conn[0].OwningProcess
        $procName = ""
        try { $procName = (Get-Process -Id $procId -ErrorAction Stop).ProcessName } catch {}
        Write-Host "  [WARN] Port $port ($svcName) occupied by PID $procId ($procName)" -ForegroundColor Yellow
        $conflicts += [PSCustomObject]@{Port=$port; Service=$svcName; PID=$procId; Process=$procName}
    }
}

if ($conflicts.Count -gt 0) {
    Write-Host ""
    Write-Host "  $($conflicts.Count) port(s) already in use." -ForegroundColor Yellow

    $shouldKill = $false
    if ($Force) {
        Write-Host "  -Force specified, killing automatically..." -ForegroundColor White
        $shouldKill = $true
    } else {
        Write-Host "  These services may already be running. Options:" -ForegroundColor White
        Write-Host "    1. Run .\scripts\stop-all.ps1 -KillByPort first, then re-run start-all" -ForegroundColor White
        Write-Host "    2. Re-run with -Force to auto-kill and continue" -ForegroundColor White
        Write-Host ""
        $answer = Read-Host "  Kill existing processes and continue? (y/N)"
        if ($answer -eq "y" -or $answer -eq "Y") {
            $shouldKill = $true
        }
    }

    if ($shouldKill) {
        foreach ($c in $conflicts) {
            try {
                Stop-Process -Id $c.PID -Force -ErrorAction Stop
                Write-Host "  [OK] Killed PID $($c.PID) ($($c.Process)) on port $($c.Port)" -ForegroundColor Green
                Start-Sleep -Milliseconds 500
            } catch {
                Write-Host "  [WARN] Cannot kill PID $($c.PID): $($_.Exception.Message)" -ForegroundColor Yellow
            }
        }
        Start-Sleep -Seconds 2
    } else {
        Write-Host "  Aborting. Please stop existing services first." -ForegroundColor Red
        exit 1
    }
} else {
    Write-Host "  [OK] All app ports are free" -ForegroundColor Green
}
Write-Host ""

# ===== 4. Build NestJS services (required for nest start --watch) =====
Write-Host "[4/6] Building NestJS services (first time required)..." -ForegroundColor Yellow

$nestjsServices = @(
    "@edu/classes-service",
    "@edu/iam-service",
    "@edu/teacher-bff",
    "@edu/core-edu-service",
    "@edu/content-service",
    "@edu/msg-service"
)

# Clean tsbuildinfo cache (incremental mode leftover causes tsc to skip emit)
$nestjsDirs = @("classes", "iam", "teacher-bff", "core-edu", "content", "msg")
foreach ($dir in $nestjsDirs) {
    $svcPath = Join-Path $ProjectRoot "services\$dir"
    if (Test-Path $svcPath) {
        Get-ChildItem -Path $svcPath -Filter "*.tsbuildinfo" -Recurse -ErrorAction SilentlyContinue |
            Remove-Item -Force -ErrorAction SilentlyContinue
    }
}

foreach ($svc in $nestjsServices) {
    Write-Host "  Building $svc..." -ForegroundColor Gray -NoNewline
    $buildResult = pnpm --filter $svc build 2>&1
    if ($LASTEXITCODE -eq 0) {
        Write-Host " [OK]" -ForegroundColor Green
    } else {
        Write-Host " [FAIL]" -ForegroundColor Red
        Write-Host "  $buildResult" -ForegroundColor DarkGray
    }
}
Write-Host ""

# ===== 5. Start application services =====
Write-Host "[5/6] Starting application services (11 windows)..." -ForegroundColor Yellow

$services = @(
    @{Title="edu-app-classes";      Cmd="pnpm"; Args=@("--filter","@edu/classes-service","dev");          Dir="$ProjectRoot"},
    @{Title="edu-app-iam";          Cmd="pnpm"; Args=@("--filter","@edu/iam-service","dev");              Dir="$ProjectRoot"},
    @{Title="edu-app-teacher-bff";  Cmd="pnpm"; Args=@("--filter","@edu/teacher-bff","dev");              Dir="$ProjectRoot"},
    @{Title="edu-app-core-edu";     Cmd="pnpm"; Args=@("--filter","@edu/core-edu-service","dev");         Dir="$ProjectRoot"},
    @{Title="edu-app-content";      Cmd="pnpm"; Args=@("--filter","@edu/content-service","dev");          Dir="$ProjectRoot"},
    @{Title="edu-app-msg";          Cmd="pnpm"; Args=@("--filter","@edu/msg-service","dev");              Dir="$ProjectRoot"},
    @{Title="edu-app-data-ana";     Cmd="uv";   Args=@("run","uvicorn","data_ana.main:app","--app-dir","src","--host","0.0.0.0","--port","3006","--reload"); Dir="$ProjectRoot\services\data-ana"; PyEnv=$true},
    @{Title="edu-app-ai";           Cmd="uv";   Args=@("run","uvicorn","ai.main:app","--app-dir","src","--host","0.0.0.0","--port","3008","--reload");       Dir="$ProjectRoot\services\ai";         PyEnv=$true},
    @{Title="edu-app-api-gateway";  Cmd="go";   Args=@("run",".");                                          Dir="$ProjectRoot\services\api-gateway"; GoEnv=$true},
    @{Title="edu-app-push-gateway"; Cmd="go";   Args=@("run",".");                                          Dir="$ProjectRoot\services\push-gateway";GoEnv=$true},
    @{Title="edu-app-teacher-portal";Cmd="pnpm";Args=@("--filter","teacher-portal","dev");                 Dir="$ProjectRoot"}
)

foreach ($svc in $services) {
    $cmdStr = "$($svc.Cmd) $($svc.Args -join ' ')"

    $psCmd = "Set-Location '$($svc.Dir)'; "

    if ($svc.PyEnv) {
        foreach ($kv in $pyEnv.GetEnumerator()) {
            $psCmd += "`$env:$($kv.Key)='$($kv.Value)'; "
        }
    }

    if ($svc.GoEnv) {
        $psCmd += "`$env:Path = 'C:\Program Files\Go\bin;' + `$env:Path; "
    }

    $psCmd += "$cmdStr; Write-Host ''; Write-Host 'Service stopped. Press any key to close...' -ForegroundColor Yellow; `$null = `$Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')"

    Start-Process -FilePath "powershell" -ArgumentList "-NoExit","-Command",$psCmd -WindowStyle Normal | Out-Null

    Write-Host "  [START] $($svc.Title)..." -ForegroundColor Green
    Start-Sleep -Milliseconds 500
}

Write-Host ""
Write-Host "  All services started in new windows. Waiting 40s for init..." -ForegroundColor Yellow
Start-Sleep -Seconds 40

# ===== 6. Health check =====
Write-Host "[6/6] Health check..." -ForegroundColor Yellow
Write-Host ""

$healthServices = @(
    @{Name="classes";      Url="http://localhost:3001/healthz"},
    @{Name="iam";          Url="http://localhost:3002/healthz"},
    @{Name="teacher-bff";  Url="http://localhost:3003/healthz"},
    @{Name="core-edu";     Url="http://localhost:3004/healthz"},
    @{Name="content";      Url="http://localhost:3005/healthz"},
    @{Name="data-ana";     Url="http://localhost:3006/healthz"},
    @{Name="msg";          Url="http://localhost:3007/healthz"},
    @{Name="ai";           Url="http://localhost:3008/healthz"},
    @{Name="api-gateway";  Url="http://localhost:8080/healthz"},
    @{Name="push-gateway"; Url="http://localhost:8081/healthz"},
    @{Name="teacher-portal";Url="http://localhost:3000/"}
)

$okCount = 0
$failCount = 0
$failedServices = @()
foreach ($svc in $healthServices) {
    $retries = 0
    $maxRetries = 3
    $success = $false
    $lastError = ""
    while ($retries -lt $maxRetries -and -not $success) {
        try {
            $null = Invoke-RestMethod -Uri $svc.Url -Method Get -TimeoutSec 5 -ErrorAction Stop
            Write-Host "  [OK] $($svc.Name)" -ForegroundColor Green
            $success = $true
            $okCount++
        } catch {
            $lastError = $_.Exception.Message
            $retries++
            if ($retries -lt $maxRetries) {
                Start-Sleep -Seconds 5
            }
        }
    }
    if (-not $success) {
        Write-Host "  [FAIL] $($svc.Name) (after $maxRetries retries: $lastError)" -ForegroundColor Red
        $failCount++
        $failedServices += $svc.Name
    }
}

Write-Host ""
Write-Host "========================================" -ForegroundColor Cyan
Write-Host "  Started: [OK] $okCount ready / [FAIL] $failCount failed" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan

if ($failCount -gt 0) {
    Write-Host ""
    Write-Host "Failed services: $($failedServices -join ', ')" -ForegroundColor Red
    Write-Host ""
    Write-Host "Troubleshooting:" -ForegroundColor Yellow
    Write-Host "  1. Check the service window for error output" -ForegroundColor White
    Write-Host "  2. Verify dependencies: pnpm install / uv sync / go mod tidy" -ForegroundColor White
    Write-Host "  3. Re-run health check: .\scripts\health-check.ps1" -ForegroundColor White
    Write-Host "  4. Stop and retry: .\scripts\stop-all.ps1 -KillByPort then .\scripts\start-all.ps1" -ForegroundColor White
    Write-Host ""
    exit 1
}

Write-Host ""
Write-Host "Next steps:" -ForegroundColor Yellow
Write-Host "  Health check:  .\scripts\health-check.ps1" -ForegroundColor White
Write-Host "  CDC test:      .\scripts\test-cdc.ps1" -ForegroundColor White
Write-Host "  Stop all:      .\scripts\stop-all.ps1" -ForegroundColor White
Write-Host ""
