# Unicode-safe update applier for LA StressLab.
# Reads update_pending.json (UTF-8). Always writes update_apply.log beside the EXE.
# IMPORTANT: keep this file ASCII-only (or UTF-8 with BOM). Windows PowerShell 5.1
# mis-parses UTF-8-without-BOM when fancy dashes / quotes are present -- window flashes and dies.
param(
    [string]$AppDir = "",
    [string]$Staging = "",
    [string]$WaitPid = "",
    [string]$ExeName = "LAStressLab.exe"
)

$ErrorActionPreference = "Continue"
$logFile = $null

function Write-Log([string]$Message) {
    $line = "[{0}] {1}" -f (Get-Date -Format "yyyy-MM-dd HH:mm:ss"), $Message
    Write-Host $line
    if ($logFile) {
        try { Add-Content -LiteralPath $logFile -Value $line -Encoding UTF8 -ErrorAction SilentlyContinue } catch {}
    }
}

function Fail-Exit([string]$Message, [int]$Code = 1) {
    Write-Log "ERROR: $Message"
    Write-Host ""
    Write-Host "Falha ao aplicar update. Veja update_apply.log nesta pasta."
    Write-Host "O app anterior deve permanecer (ou .bak)."
    Start-Sleep -Seconds 12
    exit $Code
}

function Get-PendingJob {
    param([string]$Dir)
    $pending = Join-Path $Dir "update_pending.json"
    if (-not (Test-Path -LiteralPath $pending)) { return $null }
    try {
        return (Get-Content -LiteralPath $pending -Raw -Encoding UTF8 | ConvertFrom-Json)
    } catch {
        return $null
    }
}

$scriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path
$job = Get-PendingJob -Dir $scriptRoot
if (-not $job) {
    # Pending may live in AppDir when script was started elsewhere.
    if ($AppDir) { $job = Get-PendingJob -Dir $AppDir }
}

if ($job -and $job.app_dir) { $AppDir = [string]$job.app_dir }
if (-not $AppDir) { $AppDir = $scriptRoot }
if ($job -and $job.staging) { $Staging = [string]$job.staging }
if (-not $Staging) { $Staging = Join-Path $AppDir "_update_staging" }
if ($job -and $job.exe_name) { $ExeName = [string]$job.exe_name }
if (-not $ExeName) { $ExeName = "LAStressLab.exe" }
# Prefer wait_pid from pending when launcher omitted CLI args (paths with spaces).
if ((-not $WaitPid) -and $job -and $job.wait_pid) { $WaitPid = [string]$job.wait_pid }

$logFile = Join-Path $AppDir "update_apply.log"
# Append -- never wipe LAUNCH breadcrumbs from bat/python.
Write-Log "==== LA StressLab applying update ===="
Write-Log "AppDir=$AppDir"
Write-Log "Staging=$Staging"
Write-Log "ExeName=$ExeName"
Write-Log "WaitPid=$WaitPid"
Write-Log "PSVersion=$($PSVersionTable.PSVersion)"

if ($WaitPid) {
    Write-Log "Waiting for PID $WaitPid to exit..."
    $deadline = (Get-Date).AddMinutes(4)
    while ((Get-Date) -lt $deadline) {
        $proc = Get-Process -Id ([int]$WaitPid) -ErrorAction SilentlyContinue
        if (-not $proc) { break }
        Start-Sleep -Milliseconds 500
    }
    $still = Get-Process -Id ([int]$WaitPid) -ErrorAction SilentlyContinue
    if ($still) {
        Write-Log "WARN: PID $WaitPid still alive after timeout -- trying to continue"
    } else {
        Write-Log "PID $WaitPid exited"
    }
}

# Extra settle time so Windows releases file locks on the EXE / _internal.
Start-Sleep -Seconds 3

$stagedExe = Join-Path $Staging $ExeName
if (-not (Test-Path -LiteralPath $stagedExe)) {
    # Tolerate nested folder from older zips.
    $found = Get-ChildItem -LiteralPath $Staging -Filter $ExeName -Recurse -ErrorAction SilentlyContinue | Select-Object -First 1
    if ($found) {
        Write-Log "Found nested EXE at $($found.FullName) -- promoting folder"
        $nested = $found.Directory.FullName
        Get-ChildItem -LiteralPath $nested -Force | ForEach-Object {
            $dest = Join-Path $Staging $_.Name
            if (Test-Path -LiteralPath $dest) {
                if ($_.PSIsContainer) { Remove-Item -LiteralPath $dest -Recurse -Force -ErrorAction SilentlyContinue }
                else { Remove-Item -LiteralPath $dest -Force -ErrorAction SilentlyContinue }
            }
            Move-Item -LiteralPath $_.FullName -Destination $dest -Force -ErrorAction SilentlyContinue
        }
    }
}
if (-not (Test-Path -LiteralPath $stagedExe)) {
    Fail-Exit "staging missing $ExeName under $Staging"
}

$bak = Join-Path $AppDir ($ExeName + ".bak")
$cur = Join-Path $AppDir $ExeName
if (Test-Path -LiteralPath $cur) {
    try {
        Copy-Item -LiteralPath $cur -Destination $bak -Force -ErrorAction Stop
        Write-Log "Backup OK -> $bak"
    } catch {
        Write-Log "WARN: backup failed: $($_.Exception.Message)"
    }
}

# Wait until EXE is writable (unlock).
$unlockDeadline = (Get-Date).AddMinutes(2)
while ((Get-Date) -lt $unlockDeadline) {
    try {
        if (Test-Path -LiteralPath $cur) {
            $fs = [System.IO.File]::Open($cur, 'Open', 'ReadWrite', 'None')
            $fs.Close()
        }
        break
    } catch {
        Start-Sleep -Seconds 1
    }
}

$exclude = @(
    "telegram.json",
    "update.json",
    "update_pending.json",
    "update_apply.log",
    "license.json",
    "user_profile.json",
    "workshop_logo.png",
    "adm_token.txt",
    "adm_console.json",
    "dump_delivery.json"
)

Write-Log "Robocopy $Staging -> $AppDir"
# /XD avoids copying staging into itself if nested; /XF preserves configs.
& robocopy.exe $Staging $AppDir /E /R:12 /W:2 /NFL /NDL /NJH /NJS /XD "_update_staging" /XF @exclude
$rc = $LASTEXITCODE
Write-Log "Robocopy exit=$rc"
# robocopy: 0-7 = success-ish; >=8 = failure
if ($rc -ge 8) {
    Fail-Exit "robocopy failed code $rc"
}

# Merge ADM dumps bot from the new package without wiping client results pairing.
$stagedDump = Join-Path $Staging "dump_delivery.json"
$appDump = Join-Path $AppDir "dump_delivery.json"
if (Test-Path -LiteralPath $stagedDump) {
    try {
        $newDump = Get-Content -LiteralPath $stagedDump -Raw -Encoding UTF8 | ConvertFrom-Json
        if (Test-Path -LiteralPath $appDump) {
            $oldDump = Get-Content -LiteralPath $appDump -Raw -Encoding UTF8 | ConvertFrom-Json
        } else {
            $oldDump = $newDump
        }
        if ($null -eq $oldDump.dumps) {
            $emptyDumps = New-Object PSObject
            $oldDump | Add-Member -NotePropertyName dumps -NotePropertyValue $emptyDumps -Force
        }
        if ($null -eq $oldDump.dumps.telegram) {
            $emptyTg = New-Object PSObject
            $oldDump.dumps | Add-Member -NotePropertyName telegram -NotePropertyValue $emptyTg -Force
        }
        if ($newDump.dumps -and $newDump.dumps.telegram) {
            $oldDump.dumps.telegram = $newDump.dumps.telegram
        }
        if ($newDump.telegram) {
            $oldDump.telegram = $newDump.telegram
        }
        if ($null -ne $newDump.auto_send_after_dump) {
            $oldDump.auto_send_after_dump = $newDump.auto_send_after_dump
        }
        $json = $oldDump | ConvertTo-Json -Depth 8
        Set-Content -LiteralPath $appDump -Value $json -Encoding UTF8
        Write-Log "Merged dump_delivery.json (ADM dumps only; results preserved)"
    } catch {
        Write-Log "WARN: dump_delivery merge failed -- copying staged file"
        Copy-Item -LiteralPath $stagedDump -Destination $appDump -Force -ErrorAction SilentlyContinue
    }
}

$appDataTg = Join-Path $env:LOCALAPPDATA "LAStressLab\telegram.json"
$usbTg = Join-Path $AppDir "telegram.json"
if ((Test-Path -LiteralPath $appDataTg) -and -not (Test-Path -LiteralPath $usbTg)) {
    Copy-Item -LiteralPath $appDataTg -Destination $usbTg -Force -ErrorAction SilentlyContinue
    Write-Log "Restored telegram.json from LocalAppData"
}

$pendingPath = Join-Path $AppDir "update_pending.json"
if (Test-Path -LiteralPath $pendingPath) {
    Remove-Item -LiteralPath $pendingPath -Force -ErrorAction SilentlyContinue
}

Write-Log "Cleaning staging..."
Remove-Item -LiteralPath $Staging -Recurse -Force -ErrorAction SilentlyContinue

$newExe = Join-Path $AppDir $ExeName
if (-not (Test-Path -LiteralPath $newExe)) {
    Fail-Exit "EXE missing after copy: $newExe"
}

Write-Log "Starting $ExeName ..."
try {
    Start-Process -FilePath $newExe -WorkingDirectory $AppDir -ErrorAction Stop
    Write-Log "Start-Process OK"
} catch {
    Write-Log "Start-Process failed: $($_.Exception.Message) -- trying cmd start"
    try {
        $arg = '/c start "" "' + $newExe + '"'
        Start-Process -FilePath "cmd.exe" -ArgumentList $arg -WorkingDirectory $AppDir -ErrorAction Stop
        Write-Log "cmd start OK"
    } catch {
        Fail-Exit "could not start EXE: $($_.Exception.Message)"
    }
}

Write-Log "Update apply finished OK"
Start-Sleep -Seconds 2
exit 0
