# ==============================================================================
#  lf_mri_platform -- Pull latest code and rebuild services
#  Usage:
#    .\update.ps1                  -- git pull + rebuild all containers
#    .\update.ps1 -Services o,s    -- rebuild only listed services (comma-separated)
#    .\update.ps1 -SkipGit         -- skip git pull (only rebuild)
#    .\update.ps1 -RestartSpec     -- also restart the native spectrometer
# ==============================================================================
param(
    [string]$Services  = "",    # e.g. "orchestrator,seq-interp"
    [switch]$SkipGit,
    [switch]$RestartSpec
)

$ErrorActionPreference = "Stop"
$Root    = $PSScriptRoot
$EnvFile = Join-Path $Root ".env"

function Write-Step($msg) { Write-Host "`n==> $msg" -ForegroundColor Cyan }
function Write-OK($msg)   { Write-Host "    [OK] $msg" -ForegroundColor Green }
function Write-Warn($msg) { Write-Host "    [!!] $msg" -ForegroundColor Yellow }
function Write-Fail($msg) {
    Write-Host "`n[FAIL] $msg" -ForegroundColor Red
    Write-Host "`n  Press Enter to close..." -ForegroundColor DarkGray
    $null = Read-Host
    exit 1
}

trap {
    Write-Host "`n[ERROR] $_" -ForegroundColor Red
    Write-Host "`n  Press Enter to close..." -ForegroundColor DarkGray
    $null = Read-Host
    exit 1
}


# -- 1. Git pull ---------------------------------------------------------------
if (-not $SkipGit) {
    Write-Step "Pulling latest code"
    Push-Location $Root
    try {
        $before = & git rev-parse HEAD 2>$null
        & git pull
        if ($LASTEXITCODE -ne 0) { Write-Fail "git pull failed" }
        $after = & git rev-parse HEAD 2>$null
        if ($before -eq $after) {
            Write-OK "Already up to date ($($after.Substring(0,8)))"
        } else {
            Write-OK "Updated $($before.Substring(0,8)) -> $($after.Substring(0,8))"
            Write-Host ""
            & git log --oneline "$before..$after"
        }
    } finally {
        Pop-Location
    }
}


# -- 2. Check Docker -----------------------------------------------------------
Write-Step "Checking Docker"
try { & docker info *>$null } catch {
    Write-Fail "Docker is not running. Start Docker Desktop and try again."
}
Write-OK "Docker is running"


# -- 3. Rebuild containers -----------------------------------------------------
Write-Step "Rebuilding containers"

$envArgs = if (Test-Path $EnvFile) { @("--env-file", $EnvFile) } else { @() }

if ($Services) {
    $svcList = $Services -split "," | ForEach-Object { $_.Trim() } | Where-Object { $_ }
    Write-Host "    Services: $($svcList -join ', ')" -ForegroundColor DarkGray
    & docker compose @envArgs up --build -d @svcList
} else {
    Write-Host "    Services: all" -ForegroundColor DarkGray
    & docker compose @envArgs up --build -d
}

if ($LASTEXITCODE -ne 0) { Write-Fail "docker compose up --build failed" }
Write-OK "Containers rebuilt and started"


# -- 4. Optionally restart the native spectrometer ----------------------------
if ($RestartSpec) {
    Write-Step "Restarting native spectrometer"

    $specProc = Get-Process -Name python* -ErrorAction SilentlyContinue |
                Where-Object { $_.CommandLine -like "*manage.py*runserver*" }

    if ($specProc) {
        Write-Host "    Stopping old spectrometer process (PID $($specProc.Id))..." -ForegroundColor DarkGray
        Stop-Process -Id $specProc.Id -Force
        Start-Sleep 1
        Write-OK "Old process stopped"
    } else {
        Write-Warn "No running spectrometer process found -- will start fresh"
    }

    $specDir = Join-Path $Root "services\spectrometer"
    $python  = "python"

    # Try project venv first
    $venvPy = Join-Path $Root "apps\gui\.venv\Scripts\python.exe"
    if (Test-Path $venvPy) { $python = $venvPy }

    $specPort = Get-EnvPort "SPECTROMETER_PORT" "1818"
    Write-Host "    Starting spectrometer at $specDir (port $specPort) ..." -ForegroundColor DarkGray
    Start-Process $python `
        -ArgumentList "manage.py runserver 0.0.0.0:$specPort" `
        -WorkingDirectory $specDir `
        -WindowStyle Normal

    Write-OK "Spectrometer started in new window"
}


# -- 5. Health check -----------------------------------------------------------
Write-Step "Checking service health"

function Get-EnvPort($key, $default) {
    if (Test-Path $EnvFile) {
        $line = Get-Content $EnvFile | Select-String "^$key=(\d+)"
        if ($line) { return $line.Matches[0].Groups[1].Value }
    }
    return $default
}

$checks = @(
    @{ Name = "Orchestrator";  Url = "http://localhost:$(Get-EnvPort 'ORCHESTRATOR_PORT'  '1717')/health"; Native = $false },
    @{ Name = "Seq-Interp";    Url = "http://localhost:$(Get-EnvPort 'SEQ_INTERP_PORT'    '7475')/health"; Native = $false },
    @{ Name = "Spectroscopy";  Url = "http://localhost:$(Get-EnvPort 'SPECTROSCOPY_PORT'   '8002')/health"; Native = $false },
    @{ Name = "Spectrometer*"; Url = "http://localhost:$(Get-EnvPort 'SPECTROMETER_PORT'   '1818')/api/";  Native = $true  }
)

function Test-Port($url) {
    try {
        $uri  = [System.Uri]$url
        $port = if ($uri.Port -gt 0) { $uri.Port } else { 80 }
        $tcp  = New-Object System.Net.Sockets.TcpClient
        $ar   = $tcp.BeginConnect($uri.Host, $port, $null, $null)
        $ok   = $ar.AsyncWaitHandle.WaitOne(1500, $false)
        try { $tcp.Close() } catch {}
        return $ok
    } catch { return $false }
}

$maxWait = 60; $interval = 3; $elapsed = 0
while ($elapsed -lt $maxWait) {
    $pending = @()
    foreach ($c in $checks) {
        if ($c.Native) { continue }   # native services not waited on
        if (-not (Test-Port $c.Url)) { $pending += $c.Name }
    }
    if ($pending.Count -eq 0) { break }
    Write-Host ("    ... {0}/{1} s  waiting: {2}" -f $elapsed, $maxWait, ($pending -join ", ")) -ForegroundColor DarkGray
    Start-Sleep $interval; $elapsed += $interval
}

Write-Host ""
foreach ($c in $checks) {
    $ok    = Test-Port $c.Url
    $icon  = if ($ok) { "[OK]" } else { "[--]" }
    $color = if ($ok) { "Green" } elseif ($c.Native) { "DarkGray" } else { "Yellow" }
    $suffix = if ($c.Native) { "  (native -- start manually if needed)" } else { "" }
    Write-Host ("    {0,-6} {1,-16} {2}{3}" -f $icon, $c.Name, $c.Url, $suffix) -ForegroundColor $color
}


# -- 6. Summary ----------------------------------------------------------------
Write-Host ""
Write-Host "============================================================" -ForegroundColor Green
Write-Host "  Update complete" -ForegroundColor Green
Write-Host "============================================================" -ForegroundColor Green
Write-Host ""
Write-Host "  To rebuild only specific services next time:"
Write-Host "    .\update.ps1 -Services orchestrator,seq-interp"
Write-Host ""
Write-Host "  To also restart the native spectrometer:"
Write-Host "    .\update.ps1 -RestartSpec"
Write-Host ""
Write-Host "  Press Enter to close this window..." -ForegroundColor DarkGray
$null = Read-Host
