param(
  [string]$SmokeOutput
)

$ErrorActionPreference = 'Stop'

$repoRoot = (Resolve-Path (Join-Path $PSScriptRoot '..\..')).Path
$sourcePath = Join-Path $repoRoot 'build\scripts\project-bundle-replacement-smoke.ts'
$tempRoot = Join-Path $repoRoot '.tmp\project-bundle-replacement-smoke'
$compileRoot = Join-Path $tempRoot 'compiled'
$entryPath = Join-Path $compileRoot 'build\scripts\project-bundle-replacement-smoke.js'
$compilePackagePath = Join-Path $compileRoot 'package.json'
$compileNodeModulesPath = Join-Path $compileRoot 'node_modules'
$desktopNodeModulesPath = Join-Path $repoRoot 'apps\desktop\node_modules'
$bundleRootA = Join-Path $tempRoot 'bundle-src-a'
$bundleRootB = Join-Path $tempRoot 'bundle-src-b'
$bundleRootC = Join-Path $tempRoot 'bundle-src-c'
$bundleZipPathA = Join-Path $tempRoot 'bundle-a.zip'
$bundleZipPathB = Join-Path $tempRoot 'bundle-b.zip'
$bundleZipPathC = Join-Path $tempRoot 'bundle-c.zip'
$resolvedResultPath = if ($SmokeOutput) { [System.IO.Path]::GetFullPath($SmokeOutput) } else { Join-Path $tempRoot 'result.json' }

function Write-Utf8File {
  param([string]$FilePath, [string]$Content)
  $encoding = New-Object System.Text.UTF8Encoding $false
  [System.IO.Directory]::CreateDirectory([System.IO.Path]::GetDirectoryName($FilePath)) | Out-Null
  [System.IO.File]::WriteAllText($FilePath, $Content, $encoding)
}

function Ensure-NodeModulesLink {
  param(
    [string]$LinkPath,
    [string]$TargetPath
  )

  if (Test-Path $LinkPath) {
    Remove-Item $LinkPath -Recurse -Force
  }

  if (-not (Test-Path $TargetPath)) {
    throw "Desktop node_modules was not found: $TargetPath"
  }

  New-Item -ItemType Junction -Path $LinkPath -Target $TargetPath -Force | Out-Null
}

function New-BundleFixture {
  param(
    [string]$Root,
    [string]$VariantLabel,
    [string]$SkillEntry,
    [string]$CronEntry
  )

  if (Test-Path $Root) {
    Remove-Item $Root -Recurse -Force
  }

  New-Item -ItemType Directory -Path (Join-Path (Join-Path $Root 'skills') $SkillEntry) -Force | Out-Null
  New-Item -ItemType Directory -Path (Join-Path $Root 'memory') -Force | Out-Null
  New-Item -ItemType Directory -Path (Join-Path $Root 'cron') -Force | Out-Null

  Write-Utf8File -FilePath (Join-Path $Root 'project.json') -Content (@{
    id = 'bundle-replacement-smoke'
    name = 'Bundle Replacement Smoke'
    version = '1.0.0'
    description = 'Verifies bundle replacement and rollback hardening.'
  } | ConvertTo-Json -Depth 5)
  Write-Utf8File -FilePath (Join-Path $Root 'README.md') -Content ("# Bundle Replacement Smoke`n`nReplacement variant $VariantLabel")
  Write-Utf8File -FilePath (Join-Path $Root 'memory\summary.md') -Content ("bundle replacement variant $VariantLabel")
  Write-Utf8File -FilePath (Join-Path (Join-Path (Join-Path $Root 'skills') $SkillEntry) 'SKILL.md') -Content ("# Replacement Skill $VariantLabel")
  Write-Utf8File -FilePath (Join-Path (Join-Path $Root 'cron') $CronEntry) -Content ("bundle replacement cron $VariantLabel")
}

if (-not (Test-Path $sourcePath)) {
  throw "Project bundle replacement smoke source was not found: $sourcePath"
}

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

$compileArgs = @(
  'pnpm',
  '--dir', (Join-Path $repoRoot 'apps\desktop'),
  'exec',
  'tsc',
  '--module', 'ES2022',
  '--moduleResolution', 'node',
  '--target', 'ES2022',
  '--lib', 'ES2022',
  '--types', 'node',
  '--esModuleInterop',
  '--allowSyntheticDefaultImports',
  '--skipLibCheck',
  '--outDir', $compileRoot,
  $sourcePath
)

Write-Host 'Compiling project-bundle replacement smoke with local TypeScript'
corepack @compileArgs
if ($LASTEXITCODE -ne 0) {
  exit $LASTEXITCODE
}

if (-not (Test-Path $entryPath)) {
  throw "Project bundle replacement smoke entry was not emitted: $entryPath"
}

foreach ($path in @($bundleZipPathA, $bundleZipPathB, $bundleZipPathC)) {
  if (Test-Path $path) {
    Remove-Item $path -Force
  }
}

New-BundleFixture -Root $bundleRootA -VariantLabel 'A' -SkillEntry 'replacement-skill-a' -CronEntry 'replacement-task-a.txt'
New-BundleFixture -Root $bundleRootB -VariantLabel 'B' -SkillEntry 'replacement-skill-b' -CronEntry 'replacement-task-b.txt'
New-BundleFixture -Root $bundleRootC -VariantLabel 'C' -SkillEntry 'replacement-skill-c' -CronEntry 'replacement-task-c.txt'

Compress-Archive -Path (Join-Path $bundleRootA '*') -DestinationPath $bundleZipPathA -Force
Compress-Archive -Path (Join-Path $bundleRootB '*') -DestinationPath $bundleZipPathB -Force
Compress-Archive -Path (Join-Path $bundleRootC '*') -DestinationPath $bundleZipPathC -Force

Write-Utf8File -FilePath $compilePackagePath -Content '{"type":"module"}'
Ensure-NodeModulesLink -LinkPath $compileNodeModulesPath -TargetPath $desktopNodeModulesPath

Write-Host 'Running project-bundle replacement smoke'
node $entryPath $resolvedResultPath $bundleZipPathA $bundleZipPathB $bundleZipPathC $bundleRootA $bundleRootB $bundleRootC
if ($LASTEXITCODE -ne 0) {
  exit $LASTEXITCODE
}

if (-not (Test-Path $resolvedResultPath)) {
  throw "Project bundle replacement smoke did not produce a result file: $resolvedResultPath"
}

