param(
  [string]$BaseOutputDir,
  [int]$GatewayPort = 18889,
  [string]$GatewayToken = 'qjc-bundled-runtime-token'
)

$ErrorActionPreference = 'Stop'

function Get-TrailingJson {
  param(
    [Parameter(Mandatory = $true)]
    [string]$Text
  )

  $startIndex = $Text.LastIndexOf("`n{")
  if ($startIndex -ge 0) {
    return $Text.Substring($startIndex + 1).Trim()
  }

  $startIndex = $Text.IndexOf('{')
  if ($startIndex -ge 0) {
    return $Text.Substring($startIndex).Trim()
  }

  throw 'Unable to locate JSON payload in materialize-runtime-payload output.'
}

function Invoke-MaterializeRun {
  param(
    [Parameter(Mandatory = $true)]
    [string]$Label,
    [Parameter(Mandatory = $true)]
    [string]$ScriptPath,
    [Parameter(Mandatory = $true)]
    [string]$RuntimeDir,
    [Parameter(Mandatory = $true)]
    [string]$StdoutPath,
    [Parameter(Mandatory = $true)]
    [string]$StderrPath,
    [Parameter(Mandatory = $true)]
    [int]$GatewayPort,
    [Parameter(Mandatory = $true)]
    [string]$GatewayToken
  )

  if (Test-Path $StdoutPath) {
    Remove-Item -LiteralPath $StdoutPath -Force
  }
  if (Test-Path $StderrPath) {
    Remove-Item -LiteralPath $StderrPath -Force
  }

  Write-Host "Running materialize-runtime-payload.ps1 ($Label)"
  $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
  $process = Start-Process `
    -FilePath 'powershell' `
    -ArgumentList @(
      '-ExecutionPolicy', 'Bypass',
      '-File', $ScriptPath,
      '-RuntimeDir', $RuntimeDir,
      '-GatewayPort', $GatewayPort.ToString(),
      '-GatewayToken', $GatewayToken
    ) `
    -Wait `
    -PassThru `
    -NoNewWindow `
    -RedirectStandardOutput $StdoutPath `
    -RedirectStandardError $StderrPath
  $stopwatch.Stop()

  $stdout = if (Test-Path $StdoutPath) { [string](Get-Content -Path $StdoutPath -Raw) } else { '' }
  $stderr = if (Test-Path $StderrPath) { [string](Get-Content -Path $StderrPath -Raw) } else { '' }

  if ($stdout -and $stdout.Trim()) {
    Write-Host ($stdout.TrimEnd())
  }
  if ($stderr -and $stderr.Trim()) {
    Write-Warning ($stderr.TrimEnd())
  }

  if ($process.ExitCode -ne 0) {
    throw "materialize-runtime-payload.ps1 failed during $Label with exit code $($process.ExitCode)"
  }

  $summary = Get-TrailingJson -Text $stdout | ConvertFrom-Json
  return [PSCustomObject]@{
    label = $Label
    exitCode = $process.ExitCode
    elapsedMs = [math]::Round($stopwatch.Elapsed.TotalMilliseconds, 2)
    stdoutPath = $StdoutPath
    stderrPath = $StderrPath
    stdout = $stdout
    stderr = $stderr
    summary = $summary
  }
}

$repoRoot = (Resolve-Path (Join-Path $PSScriptRoot '..\..')).Path
if (-not $BaseOutputDir) {
  $BaseOutputDir = Join-Path $repoRoot '.tmp\mrcs'
}
$BaseOutputDir = [System.IO.Path]::GetFullPath($BaseOutputDir)
$runtimeDir = Join-Path $BaseOutputDir 'rt'
$logsDir = Join-Path $BaseOutputDir 'logs'
$materializeScript = Join-Path $repoRoot 'build\scripts\materialize-runtime-payload.ps1'
$manifestPath = Join-Path $runtimeDir 'runtime-manifest.json'
$pythonManifestPath = Join-Path $runtimeDir 'python\python-manifest.json'
$ffmpegPath = Join-Path $runtimeDir 'ffmpeg\bin\ffmpeg.exe'

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

$firstRun = Invoke-MaterializeRun `
  -Label 'first-run' `
  -ScriptPath $materializeScript `
  -RuntimeDir $runtimeDir `
  -StdoutPath (Join-Path $logsDir 'first-run.stdout.log') `
  -StderrPath (Join-Path $logsDir 'first-run.stderr.log') `
  -GatewayPort $GatewayPort `
  -GatewayToken $GatewayToken

if (-not $firstRun.summary.ok) {
  throw 'First materialization run did not report ok=true.'
}
if ($firstRun.summary.cacheHit) {
  throw 'First materialization run unexpectedly reported cacheHit=true.'
}
if (-not ($firstRun.stdout -match 'Upgrading pip in bundled Python runtime')) {
  throw 'First materialization run did not perform the pip upgrade step.'
}
if (-not ($firstRun.stdout -match 'Installing locked runtime dependencies')) {
  throw 'First materialization run did not install locked runtime dependencies.'
}
if (-not (Test-Path $manifestPath)) {
  throw "Expected runtime manifest at $manifestPath after first run."
}
if (-not (Test-Path $pythonManifestPath)) {
  throw "Expected Python manifest at $pythonManifestPath after first run."
}
if (-not (Test-Path $ffmpegPath)) {
  throw "Expected bundled ffmpeg at $ffmpegPath after first run."
}

$secondRun = Invoke-MaterializeRun `
  -Label 'second-run' `
  -ScriptPath $materializeScript `
  -RuntimeDir $runtimeDir `
  -StdoutPath (Join-Path $logsDir 'second-run.stdout.log') `
  -StderrPath (Join-Path $logsDir 'second-run.stderr.log') `
  -GatewayPort $GatewayPort `
  -GatewayToken $GatewayToken

if (-not $secondRun.summary.ok) {
  throw 'Second materialization run did not report ok=true.'
}
if (-not $secondRun.summary.cacheHit) {
  throw 'Second materialization run did not report cacheHit=true.'
}
if ($secondRun.summary.materializationKey -ne $firstRun.summary.materializationKey) {
  throw 'Materialization key changed between the first and second run.'
}
if (-not ($secondRun.stdout -match 'Reusing bundled runtime payload')) {
  throw 'Second materialization run did not report runtime payload reuse.'
}
if ($secondRun.stdout -match 'Upgrading pip in bundled Python runtime') {
  throw 'Second materialization run unexpectedly reran the pip upgrade step.'
}
if ($secondRun.stdout -match 'Installing locked runtime dependencies') {
  throw 'Second materialization run unexpectedly reinstalled locked runtime dependencies.'
}

[PSCustomObject]@{
  ok = $true
  runtimeDir = $runtimeDir
  manifestPath = $manifestPath
  firstRun = [PSCustomObject]@{
    cacheHit = $firstRun.summary.cacheHit
    elapsedMs = $firstRun.elapsedMs
    materializationKey = $firstRun.summary.materializationKey
    stdoutPath = $firstRun.stdoutPath
    stderrPath = $firstRun.stderrPath
  }
  secondRun = [PSCustomObject]@{
    cacheHit = $secondRun.summary.cacheHit
    elapsedMs = $secondRun.elapsedMs
    materializationKey = $secondRun.summary.materializationKey
    stdoutPath = $secondRun.stdoutPath
    stderrPath = $secondRun.stderrPath
  }
} | ConvertTo-Json -Depth 10
