param(
  [string]$ResultPath
)

$ErrorActionPreference = "Stop"
$root = Split-Path -Parent $PSScriptRoot
$candidateDirectory = Join-Path $root "dist\release-candidate"
$manifestPath = Join-Path $candidateDirectory "release-manifest.json"
$stage = "candidate-verification"
$verificationSucceeded = $false

function Write-SafeResult([bool]$ok, [string]$currentStage) {
  if (-not $ResultPath) { return }
  $distDirectory = [IO.Path]::GetFullPath((Join-Path $root "dist"))
  $resolvedResult = [IO.Path]::GetFullPath($ResultPath)
  if (-not $resolvedResult.StartsWith($distDirectory + [IO.Path]::DirectorySeparatorChar, [StringComparison]::OrdinalIgnoreCase)) {
    throw "Lifecycle result path must stay inside dist."
  }
  $payload = [ordered]@{ ok = $ok; stage = $currentStage } | ConvertTo-Json -Compress
  [IO.File]::WriteAllText($resolvedResult, $payload, (New-Object Text.UTF8Encoding($false)))
}

Write-SafeResult $false $stage

Push-Location $root
try {
  & npm.cmd run release:verify
  $releaseVerificationExitCode = $LASTEXITCODE
} finally { Pop-Location }
if ($releaseVerificationExitCode -ne 0) { throw "Release candidate verification failed." }

$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
$principal = New-Object Security.Principal.WindowsPrincipal($identity)
if (-not $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
  throw "Windows clean-user lifecycle verification requires an elevated PowerShell session."
}

$manifest = Get-Content -LiteralPath $manifestPath -Raw | ConvertFrom-Json
if ($manifest.distribution.windows.channel -ne "public-unsigned" -or
    $manifest.artifacts.windows.signing -ne "unsigned") {
  throw "Windows candidate is not the approved public unsigned release."
}
$stage = "create-user"
Write-SafeResult $false $stage
$installer = Join-Path $candidateDirectory $manifest.artifacts.windows.file
$userName = "crmrc-" + ([Guid]::NewGuid().ToString("N").Substring(0, 8))
$passwordText = "Crm!" + [Guid]::NewGuid().ToString("N") + "aA1"
$password = ConvertTo-SecureString $passwordText -AsPlainText -Force
$credential = New-Object Management.Automation.PSCredential(".\$userName", $password)
$harness = Join-Path $env:ProgramData ("CodeRemoteManagerLifecycle-" + [Guid]::NewGuid().ToString("N"))
$installerCopy = Join-Path $harness "CodeRemoteManagerSetup.exe"
$childScript = Join-Path $harness "lifecycle.ps1"
$childResultPath = Join-Path $harness "result.json"
$createdUser = $false
$testSid = $null

$childSource = @'
param(
  [Parameter(Mandatory = $true)][string]$Installer,
  [Parameter(Mandatory = $true)][string]$Result
)

$ErrorActionPreference = "Stop"
$appDirectory = Join-Path $env:LOCALAPPDATA "Programs\Code Remote Manager"
$retainedDirectory = Join-Path $env:LOCALAPPDATA "CodeRemoteManager"
$configPath = Join-Path $retainedDirectory "config.local.json"
$startupKey = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run"
$startupName = "Code Remote Manager Host"
$nodePath = Join-Path $appDirectory "node.exe"
$hostScript = Join-Path $appDirectory "start-host.vbs"
$markerPath = Join-Path $retainedDirectory "retained-marker.txt"
$backupPath = Join-Path $retainedDirectory "config-backups\retained-marker.json"
$authPath = Join-Path $retainedDirectory "data\security\device-auth.json"
$workspacePath = Join-Path $retainedDirectory "workspace"
$userDataPath = Join-Path $workspacePath "retained-marker.txt"
$childStage = "initial-install"

function Write-ChildResult([bool]$ok) {
  $payload = [ordered]@{ ok = $ok; stage = $childStage } | ConvertTo-Json -Compress
  [IO.File]::WriteAllText($Result, $payload, (New-Object Text.UTF8Encoding($false)))
}

Write-ChildResult $false

function Reserve-LoopbackPort {
  $listener = New-Object Net.Sockets.TcpListener([Net.IPAddress]::Loopback, 0)
  $listener.Start()
  try { return $listener.LocalEndpoint.Port } finally { $listener.Stop() }
}

function Run-Installer([string]$file, [string[]]$arguments) {
  $process = Start-Process -FilePath $file -ArgumentList $arguments -Wait -PassThru
  if ($process.ExitCode -ne 0) { throw "Installer lifecycle command failed." }
}

function Stop-InstalledHost {
  Get-CimInstance Win32_Process | Where-Object {
    $_.ExecutablePath -and $_.ExecutablePath.Equals($nodePath, [StringComparison]::OrdinalIgnoreCase)
  } | ForEach-Object {
    Invoke-CimMethod -InputObject $_ -MethodName Terminate -ErrorAction SilentlyContinue | Out-Null
  }
  Start-Sleep -Milliseconds 500
}

function Start-And-VerifyHost([int]$pwaPort) {
  $env:CODE_REMOTE_MANAGER_PWA_PORT = [string]$pwaPort
  Start-Process -FilePath "wscript.exe" -ArgumentList ('"' + $hostScript + '"') | Out-Null
  $deadline = (Get-Date).AddSeconds(30)
  while ((Get-Date) -lt $deadline) {
    try {
      $health = Invoke-RestMethod -UseBasicParsing -Uri ("http://127.0.0.1:" + $pwaPort + "/api/health") -TimeoutSec 2
      if ($health.ok -eq $true) { return }
    } catch {}
    Start-Sleep -Milliseconds 200
  }
  throw "Installed host health check timed out."
}

try {
  if (Test-Path -LiteralPath $appDirectory) { throw "Clean user already has an installation." }
  if (Test-Path -LiteralPath $retainedDirectory) { throw "Clean user already has retained data." }

  Run-Installer $Installer @("/VERYSILENT", "/SUPPRESSMSGBOXES", "/NORESTART", "/SP-")
  $childStage = "installed-layout"
  Write-ChildResult $false
  foreach ($required in @("CodeRemoteManager.exe", "node.exe", "host\host.mjs", "app\backend\src\index.js", "app\pwa\index.html", "unins000.exe")) {
    if (-not (Test-Path -LiteralPath (Join-Path $appDirectory $required))) {
      throw "Installed program layout is incomplete."
    }
  }
  $startupValue = (Get-ItemProperty -LiteralPath $startupKey -Name $startupName).$startupName
  if ($startupValue -notmatch "start-host\.vbs") { throw "Current-user startup entry is missing." }

  New-Item -ItemType Directory -Force -Path (Split-Path -Parent $backupPath), (Split-Path -Parent $authPath), $workspacePath | Out-Null
  [IO.File]::WriteAllText($markerPath, "retained-marker", (New-Object Text.UTF8Encoding($false)))
  [IO.File]::WriteAllText($backupPath, '{"kind":"retained-marker"}', (New-Object Text.UTF8Encoding($false)))
  [IO.File]::WriteAllText($authPath, '{"schemaVersion":1,"pendingPairing":null,"devices":[]}', (New-Object Text.UTF8Encoding($false)))
  [IO.File]::WriteAllText($userDataPath, "retained-marker", (New-Object Text.UTF8Encoding($false)))

  $backendPort = Reserve-LoopbackPort
  $pwaPort = Reserve-LoopbackPort
  $config = [ordered]@{
    codexCliPath = "codex.cmd"
    engine = "fake"
    bindHost = "127.0.0.1"
    port = $backendPort
    allowedOrigins = @("http://127.0.0.1:$pwaPort")
    dataDir = (Join-Path $retainedDirectory "data")
    accounts = @()
    workspaces = @([ordered]@{ id = "clean-user"; label = "Clean user"; path = $workspacePath })
  }
  [IO.File]::WriteAllText($configPath, ($config | ConvertTo-Json -Depth 6), (New-Object Text.UTF8Encoding($false)))

  $childStage = "first-start"
  Write-ChildResult $false
  Start-And-VerifyHost $pwaPort
  Stop-InstalledHost
  $childStage = "restart"
  Write-ChildResult $false
  Start-And-VerifyHost $pwaPort
  Stop-InstalledHost

  $childStage = "in-place-update"
  Write-ChildResult $false
  Run-Installer $Installer @("/VERYSILENT", "/SUPPRESSMSGBOXES", "/NORESTART", "/SP-")
  foreach ($retained in @($markerPath, $backupPath, $authPath, $userDataPath, $configPath)) {
    if (-not (Test-Path -LiteralPath $retained)) { throw "In-place update removed retained data." }
  }
  $childStage = "post-update-start"
  Write-ChildResult $false
  Start-And-VerifyHost $pwaPort
  Stop-InstalledHost

  $childStage = "uninstall"
  Write-ChildResult $false
  Run-Installer (Join-Path $appDirectory "unins000.exe") @("/VERYSILENT", "/SUPPRESSMSGBOXES", "/NORESTART")
  if (Test-Path -LiteralPath $appDirectory) { throw "Uninstall retained program files." }
  $remainingStartup = Get-ItemProperty -LiteralPath $startupKey -Name $startupName -ErrorAction SilentlyContinue
  if ($null -ne $remainingStartup) { throw "Uninstall retained the startup entry." }
  $childStage = "retained-data"
  Write-ChildResult $false
  foreach ($retained in @($markerPath, $backupPath, $authPath, $userDataPath, $configPath)) {
    if (-not (Test-Path -LiteralPath $retained)) { throw "Uninstall removed retained user data." }
  }

  $childStage = "complete"
  Write-ChildResult $true
} catch {
  Write-ChildResult $false
  exit 1
} finally {
  Stop-InstalledHost
}
'@

try {
  New-Item -ItemType Directory -Force -Path $harness | Out-Null
  Copy-Item -LiteralPath $installer -Destination $installerCopy
  Set-Content -LiteralPath $childScript -Value $childSource -Encoding UTF8

  New-LocalUser -Name $userName -Password $password -AccountNeverExpires -Description "Temporary CRM release test" | Out-Null
  $createdUser = $true
  $localUser = Get-LocalUser -Name $userName
  $testSid = $localUser.SID.Value
  $usersGroup = Get-LocalGroup -SID "S-1-5-32-545"
  Add-LocalGroupMember -Group $usersGroup -Member $localUser
  & icacls.exe $harness /grant ("*" + $testSid + ":(OI)(CI)F") /Q | Out-Null
  if ($LASTEXITCODE -ne 0) { throw "Temporary lifecycle directory permission failed." }

  $stage = "child-lifecycle"
  Write-SafeResult $false $stage
  $arguments = "-NoProfile -ExecutionPolicy Bypass -File `"$childScript`" -Installer `"$installerCopy`" -Result `"$childResultPath`""
  $process = Start-Process -FilePath "powershell.exe" -ArgumentList $arguments -Credential $credential -LoadUserProfile -Wait -PassThru
  $result = if (Test-Path -LiteralPath $childResultPath) { Get-Content -LiteralPath $childResultPath -Raw | ConvertFrom-Json } else { $null }
  if ($process.ExitCode -ne 0 -or $result.ok -ne $true) {
    if ($result -and [string]$result.stage -match '^[a-z-]{1,40}$') {
      Write-SafeResult $false ("child-" + [string]$result.stage)
    } else {
      Write-SafeResult $false "child-process"
    }
    throw "Windows clean-user lifecycle verification failed."
  }
  $verificationSucceeded = $true
  Write-Host "Verified public unsigned Windows install, in-place update, restart, uninstall, and retained data."
} finally {
  $passwordText = $null
  $credential = $null
  if ($createdUser) {
    Get-LocalUser -Name $userName -ErrorAction SilentlyContinue | Remove-LocalUser
  }
  if ($testSid) {
    Start-Sleep -Milliseconds 500
    Get-CimInstance Win32_UserProfile -Filter ("SID='" + $testSid + "'") -ErrorAction SilentlyContinue |
      Where-Object { -not $_.Loaded } | Remove-CimInstance -ErrorAction SilentlyContinue
  }
  Remove-Item -LiteralPath $harness -Recurse -Force -ErrorAction SilentlyContinue
  if ($verificationSucceeded) { Write-SafeResult $true "complete" }
}
