param(
  [string]$SetupExe,
  [string]$BaseOutputDir,
  [int]$InstallTimeoutSeconds = 480,
  [int]$TimeoutSeconds = 240,
  [switch]$RunInstalledAppSmokeOnRelocatedInstall
)

$ErrorActionPreference = 'Stop'

$repoRoot = (Resolve-Path (Join-Path $PSScriptRoot '..\..')).Path
$installerSmokeScript = Join-Path $repoRoot 'build\scripts\installer-smoke.ps1'
$installerDir = Join-Path $repoRoot 'dist\installer'

if (-not $SetupExe) {
  $latestSetup = Get-ChildItem -Path $installerDir -Filter '*-Setup-*.exe' |
    Sort-Object LastWriteTime -Descending |
    Select-Object -First 1

  if (-not $latestSetup) {
    throw "No installer exe found under $installerDir"
  }

  $SetupExe = $latestSetup.FullName
}

$SetupExe = (Resolve-Path $SetupExe).Path

if (-not $BaseOutputDir) {
  $BaseOutputDir = Join-Path $repoRoot '.tmp\installer-path-change-smoke'
}
$BaseOutputDir = [System.IO.Path]::GetFullPath($BaseOutputDir)

if (Test-Path $BaseOutputDir) {
  Remove-Item -Path $BaseOutputDir -Recurse -Force -ErrorAction SilentlyContinue
}
New-Item -ItemType Directory -Force -Path $BaseOutputDir | Out-Null

$initialInstallDir = Join-Path $BaseOutputDir 'existing\千匠问天'
$relocatedInstallDir = Join-Path $BaseOutputDir 'relocated\千匠问天'
$initialResultPath = Join-Path $BaseOutputDir 'initial-install-result.json'
$relocatedResultPath = Join-Path $BaseOutputDir 'relocated-install-result.json'
$summaryPath = Join-Path $BaseOutputDir 'installer-path-change-summary.json'

$commonArgs = @(
  '-SetupExe', $SetupExe,
  '-InstallTimeoutSeconds', $InstallTimeoutSeconds,
  '-TimeoutSeconds', $TimeoutSeconds
)

Write-Host "Installing baseline package to $initialInstallDir"
powershell -ExecutionPolicy Bypass -File $installerSmokeScript @commonArgs `
  -InstallDir $initialInstallDir `
  -SmokeOutput $initialResultPath `
  -SkipInstalledAppSmoke
if ($LASTEXITCODE -ne 0) {
  exit $LASTEXITCODE
}

$initialResult = Get-Content -LiteralPath $initialResultPath | ConvertFrom-Json
if (-not $initialResult.ok) {
  throw 'Initial installer materialization did not report ok=true.'
}
if (-not $initialResult.uninstallerExists) {
  throw 'Initial installer materialization did not write the uninstaller.'
}

Write-Host "Installing same package to relocated path $relocatedInstallDir"
$relocatedArgs = @(
  '-SetupExe', $SetupExe,
  '-InstallDir', $relocatedInstallDir,
  '-SmokeOutput', $relocatedResultPath,
  '-InstallTimeoutSeconds', $InstallTimeoutSeconds,
  '-TimeoutSeconds', $TimeoutSeconds,
  '-AdditionalPriorInstallDirs', $initialInstallDir
)
if (-not $RunInstalledAppSmokeOnRelocatedInstall) {
  $relocatedArgs += '-SkipInstalledAppSmoke'
}

powershell -ExecutionPolicy Bypass -File $installerSmokeScript @relocatedArgs
if ($LASTEXITCODE -ne 0) {
  exit $LASTEXITCODE
}

$relocatedResult = Get-Content -LiteralPath $relocatedResultPath | ConvertFrom-Json
if (-not $relocatedResult.ok) {
  throw 'Relocated installer run did not report ok=true.'
}
if (-not $relocatedResult.uninstallerExists) {
  throw 'Relocated installer run did not write the uninstaller.'
}

$priorPathEvidence = @($relocatedResult.installerStage.preflight.additionalPriorInstallObservations)
if ($priorPathEvidence.Count -lt 1) {
  throw 'Relocated installer run did not record any prior install path observation before reinstall.'
}
if (-not $priorPathEvidence[0].uninstallerExists) {
  throw 'Relocated installer run did not observe a prior install directory with an existing uninstaller before reinstall.'
}

$summary = [ordered]@{
  ok = $true
  setupExe = $SetupExe
  baseOutputDir = $BaseOutputDir
  initialInstallDir = $initialInstallDir
  relocatedInstallDir = $relocatedInstallDir
  initialInstallResult = $initialResultPath
  relocatedInstallResult = $relocatedResultPath
  priorInstallEvidenceCount = @($relocatedResult.installerStage.preflight.priorInstallEvidence).Count
  priorPathEvidenceCount = $priorPathEvidence.Count
  relocatedInstallerExitCode = $relocatedResult.installerExitCode
  relocatedFileCount = $relocatedResult.fileCount
  relocatedUninstallerExists = $relocatedResult.uninstallerExists
  relocatedFailureStage = $relocatedResult.failureStage
  relocatedFailureClassification = $relocatedResult.failureClassification
}

[System.IO.File]::WriteAllText($summaryPath, ($summary | ConvertTo-Json -Depth 12), (New-Object System.Text.UTF8Encoding $false))
Write-Output ($summary | ConvertTo-Json -Depth 12)
