#!/usr/bin/env pwsh
<#
.SYNOPSIS
    Automatic CNPERP Application Update
.DESCRIPTION
    Pulls latest code, updates dependencies, runs pending migrations,
    bumps version.txt, and restarts the CNPERP Windows service.
    Designed for scheduled/unattended execution. Logs everything for audit.
.PARAMETER LogPath
    Override log file path (default: <AppRoot>/logs/auto_update.log)
.PARAMETER Branch
    Git branch to pull from (default: main)
.EXAMPLE
    .\auto_update.ps1
    .\auto_update.ps1 -Branch "release/1.2"
#>

param(
    [string]$LogPath  = "",
    [string]$Branch   = "main"
)

$ErrorActionPreference = "Stop"

# ── Dynamic paths — no hardcoding ──────────────────────────────────────────
$AppRoot  = Split-Path -Parent $PSScriptRoot          # parent of /deploy/
$VenvPy   = Join-Path $AppRoot ".venv\Scripts\python.exe"
$LogDir   = Join-Path $AppRoot "logs"
if (-not $LogPath) { $LogPath = Join-Path $LogDir "auto_update.log" }
$VersionFile = Join-Path $AppRoot "version.txt"
$MigrationsDir = Join-Path $AppRoot "migrations"
$LockFile    = Join-Path $LogDir "auto_update.lock"

if (-not (Test-Path $LogDir)) { New-Item -ItemType Directory -Path $LogDir -Force | Out-Null }

$ScriptStart = Get-Date

function Write-Log {
    param([string]$Message, [ValidateSet("INFO","SUCCESS","WARNING","ERROR")][string]$Level = "INFO")
    $entry = "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] [$Level] $Message"
    Add-Content -Path $LogPath -Value $entry -Force
    Write-Output $entry
}

function Get-CurrentVersion {
    if (Test-Path $VersionFile) { return (Get-Content $VersionFile -Raw).Trim() }
    return "0.0.0"
}

try {
    Set-Content -Path $LockFile -Value "started=$(Get-Date -Format o)" -Force
    Write-Log "════════════════════════════════════════" INFO
    Write-Log "CNPERP Auto-Update Started" INFO
    Write-Log "App root : $AppRoot" INFO
    Write-Log "Branch   : $Branch" INFO
    Write-Log "Version  : $(Get-CurrentVersion)" INFO
    Write-Log "════════════════════════════════════════" INFO

    if (-not (Test-Path $AppRoot)) { throw "App root not found: $AppRoot" }
    Set-Location $AppRoot

    if (-not (Test-Path ".git")) { throw "Not a git repository at $AppRoot" }

    # ── 1. Pre-update database backup ──────────────────────────────────────
    Write-Log "Step 1/6 — Creating pre-update backup..." INFO
    try {
        $stamp = Get-Date -Format "yyyyMMdd_HHmmss"
        & $VenvPy -c @"
from app.services.backup_service import BackupService
from app.core.database import SessionLocal
db = SessionLocal()
try:
    BackupService(db).create_backup('pre_update_$stamp')
    print('Backup OK')
finally:
    db.close()
"@ 2>&1 | ForEach-Object { Write-Log "  $_" }
        Write-Log "Backup completed" SUCCESS
    } catch {
        Write-Log "Backup failed (non-fatal): $_" WARNING
    }

    # ── 2. Stash local changes ───────────────────────────────────────────
    Write-Log "Step 2/6 — Stashing local changes..." INFO
    git stash push -m "Auto-stash before update $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" 2>&1 |
        ForEach-Object { Write-Log "  $_" }

    # ── 3. Fetch and check for updates ──────────────────────────────────
    Write-Log "Step 3/6 — Fetching from origin/$Branch..." INFO
    git fetch origin 2>&1 | ForEach-Object { Write-Log "  $_" }

    $pending = (git log "HEAD..origin/$Branch" --oneline 2>&1 | Where-Object { $_ -match '\S' })
    $commitCount = @($pending).Count

    if ($commitCount -eq 0) {
        Write-Log "Already on latest — nothing to pull." INFO
        Write-Log "════════════════════════════════════════" SUCCESS
        Write-Log "Auto-update completed (no changes)" SUCCESS
        exit 0
    }

    Write-Log "$commitCount new commit(s) to pull:" INFO
    $pending | ForEach-Object { Write-Log "  + $_" INFO }

    # ── 4. Pull latest code ──────────────────────────────────────────────
    Write-Log "Step 4/6 — Pulling latest code..." INFO
    $pull = git pull origin $Branch 2>&1
    if ($LASTEXITCODE -ne 0) { throw "git pull failed:`n$pull" }
    Write-Log "Code updated." SUCCESS

    # ── 5. Update Python dependencies ───────────────────────────────────
    Write-Log "Step 5/6 — Updating dependencies..." INFO
    $pip = & $VenvPy -m pip install -r (Join-Path $AppRoot "requirements.txt") --upgrade --quiet 2>&1
    if ($LASTEXITCODE -ne 0) { throw "pip install failed:`n$pip" }
    Write-Log "Dependencies up to date." SUCCESS

    # ── 5b. Run pending migrations ───────────────────────────────────────
    Write-Log "Step 5b — Running pending migrations..." INFO
    if (Test-Path $MigrationsDir) {
        $migrations = Get-ChildItem -Path $MigrationsDir -Filter "*.py" |
                      Where-Object { $_.Name -notmatch "^__" } |
                      Sort-Object Name
        foreach ($m in $migrations) {
            Write-Log "  Running: $($m.Name)" INFO
            $out = & $VenvPy $m.FullName 2>&1
            if ($LASTEXITCODE -ne 0) {
                Write-Log "  Migration warning ($($m.Name)): $out" WARNING
            } else {
                Write-Log "  Done: $($m.Name)" SUCCESS
            }
        }
    } else {
        Write-Log "  No migrations directory found — skipping." INFO
    }

    # ── 6. Restart service ───────────────────────────────────────────────
    Write-Log "Step 6/6 — Restarting CNPERP service..." INFO
    $svc = Get-Service -Name "CNPERP" -ErrorAction SilentlyContinue
    if ($svc) {
        Stop-Service -Name "CNPERP" -Force -ErrorAction SilentlyContinue
        Start-Sleep -Seconds 3
        Start-Service -Name "CNPERP"
        Start-Sleep -Seconds 3
        $status = (Get-Service -Name "CNPERP").Status
        if ($status -eq "Running") {
            Write-Log "Service restarted and running." SUCCESS
        } else {
            throw "Service did not start. Status: $status"
        }
    } else {
        Write-Log "Windows Service 'CNPERP' not found — restart manually." WARNING
        Write-Log "Command: uvicorn app.main:app --host 0.0.0.0 --port 8010" WARNING
    }

    # ── Done ─────────────────────────────────────────────────────────────
    $elapsed = [math]::Round((New-TimeSpan -Start $ScriptStart -End (Get-Date)).TotalSeconds, 1)
    $lastCommit = git log -1 --pretty=format:"%h — %s"

    Write-Log "════════════════════════════════════════" SUCCESS
    Write-Log "Auto-update completed successfully!" SUCCESS
    Write-Log "  Commits pulled : $commitCount" INFO
    Write-Log "  Last commit    : $lastCommit" INFO
    Write-Log "  Version        : $(Get-CurrentVersion)" INFO
    Write-Log "  Duration       : ${elapsed}s" INFO
    Write-Log "════════════════════════════════════════" SUCCESS

} catch {
    Write-Log "ERROR: $($_.Exception.Message)" ERROR
    Write-Log "Stack: $($_.ScriptStackTrace)" ERROR
    Write-Log "════════════════════════════════════════" ERROR
    Write-Log "Auto-update FAILED at $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" ERROR
    exit 1
} finally {
    if (Test-Path $LockFile) { Remove-Item $LockFile -Force -ErrorAction SilentlyContinue }
}
