#Requires -Version 5.1
<#
  AIndex Windows installer (PowerShell).
  Mirrors install.sh: downloads the signed Windows release archive, verifies the
  SHA-256 checksum (always) and the Ed25519 signature (if openssl is available),
  extracts the binary, and adds it to your user PATH.

  Env overrides: AI_INDEXER_VERSION, AI_INDEXER_INSTALL_DIR, AI_INDEXER_SUPPORT_DIR,
  AI_INDEXER_RELEASE_BASE, AI_INDEXER_TARGET, AI_INDEXER_SKIP_CHECKSUM,
  AI_INDEXER_SKIP_SIGNATURE.
#>
$ErrorActionPreference = 'Stop'

$AppName     = 'ai-indexer'
$BinName     = 'ai-indexer-mcp.exe'
$Version     = if ($env:AI_INDEXER_VERSION) { $env:AI_INDEXER_VERSION } else { 'latest' }
$InstallDir  = if ($env:AI_INDEXER_INSTALL_DIR) { $env:AI_INDEXER_INSTALL_DIR } else { Join-Path $env:LOCALAPPDATA 'ai-indexer\bin' }
$SupportDir  = if ($env:AI_INDEXER_SUPPORT_DIR) { $env:AI_INDEXER_SUPPORT_DIR } else { Join-Path $env:USERPROFILE '.ai-indexer' }
$ReleaseBase = if ($env:AI_INDEXER_RELEASE_BASE) { $env:AI_INDEXER_RELEASE_BASE } else { 'https://aindex.floriansola.fr/releases' }

# Windows releases are published for x64 and ARM64.
$processorArch = if ($env:PROCESSOR_ARCHITEW6432) { $env:PROCESSOR_ARCHITEW6432 } else { $env:PROCESSOR_ARCHITECTURE }
$arch = switch ($processorArch.ToUpperInvariant()) {
  'AMD64' { 'x86_64' }
  'ARM64' { 'aarch64' }
  default { throw "Unsupported Windows architecture: $processorArch. Use x64 or ARM64 Windows." }
}
$target = if ($env:AI_INDEXER_TARGET) { $env:AI_INDEXER_TARGET } else { "$arch-pc-windows-msvc" }

$tag = if ($Version -eq 'latest') { 'latest' } elseif ($Version.StartsWith('v')) { $Version } else { "v$Version" }
$archive = "$AppName-$tag-$target.zip"
$tmp = Join-Path $env:TEMP "$AppName-install-$PID"
New-Item -ItemType Directory -Force -Path $tmp, $InstallDir | Out-Null

try {
  $url = "$ReleaseBase/$tag/$archive"
  $archivePath = Join-Path $tmp $archive

  # Manifest sanity check (don't hard-fail if it is unreachable).
  try {
    $manifest = Invoke-RestMethod -Uri "$ReleaseBase/$tag/release.json" -UseBasicParsing
    if ($manifest.assets -and -not ($manifest.assets.name -contains $archive)) {
      throw "No published AIndex archive for target: $target. See $ReleaseBase/$tag/release.json"
    }
  } catch { Write-Warning "Could not read release manifest: $($_.Exception.Message)" }

  Write-Host "Downloading $url"
  Invoke-WebRequest -Uri $url -OutFile $archivePath -UseBasicParsing

  if ($env:AI_INDEXER_SKIP_CHECKSUM -ne '1') {
    $sumPath = "$archivePath.sha256"
    Invoke-WebRequest -Uri "$url.sha256" -OutFile $sumPath -UseBasicParsing
    $expected = ((Get-Content $sumPath -Raw) -split '\s+')[0].Trim().ToLower()
    $actual = (Get-FileHash -Algorithm SHA256 -Path $archivePath).Hash.ToLower()
    if ($expected -ne $actual) { throw "Checksum mismatch: expected $expected, got $actual" }
    Write-Host "Verified SHA-256 checksum."
  }

  if ($env:AI_INDEXER_SKIP_SIGNATURE -ne '1') {
    $openssl = Get-Command openssl -ErrorAction SilentlyContinue
    if ($openssl) {
      Invoke-WebRequest -Uri "$url.sig" -OutFile "$archivePath.sig" -UseBasicParsing
      Invoke-WebRequest -Uri "$ReleaseBase/$tag/release-public-key.txt" -OutFile "$tmp\pub.txt" -UseBasicParsing
      function ConvertFrom-B64Url([string]$v) {
        $v = ($v -replace '\s', '') -replace '-', '+' -replace '_', '/'
        switch ($v.Length % 4) { 2 { $v += '==' } 3 { $v += '=' } }
        [Convert]::FromBase64String($v)
      }
      $pub = ConvertFrom-B64Url (Get-Content "$tmp\pub.txt" -Raw)
      $sig = ConvertFrom-B64Url (Get-Content "$archivePath.sig" -Raw)
      if ($pub.Length -ne 32) { throw 'release public key must be 32 raw Ed25519 bytes' }
      if ($sig.Length -ne 64) { throw 'release signature must be 64 raw Ed25519 bytes' }
      $prefix = [byte[]]@(0x30,0x2a,0x30,0x05,0x06,0x03,0x2b,0x65,0x70,0x03,0x21,0x00)
      [IO.File]::WriteAllBytes("$tmp\pub.der", $prefix + $pub)
      [IO.File]::WriteAllBytes("$archivePath.sig.bin", $sig)
      & openssl pkey -pubin -inform DER -in "$tmp\pub.der" -out "$tmp\pub.pem" | Out-Null
      & openssl pkeyutl -verify -pubin -inkey "$tmp\pub.pem" -rawin -in $archivePath -sigfile "$archivePath.sig.bin" | Out-Null
      if ($LASTEXITCODE -ne 0) { throw "Release signature verification failed for $archive" }
      Write-Host "Verified release signature for $archive"
    } else {
      Write-Warning "openssl not found: skipping Ed25519 signature check (checksum still verified). Install openssl or set AI_INDEXER_SKIP_SIGNATURE=1 to silence."
    }
  }

  Expand-Archive -Path $archivePath -DestinationPath $tmp -Force
  $extractedBin = Join-Path $tmp $BinName
  if (-not (Test-Path $extractedBin)) { throw "$BinName missing from archive" }

  Copy-Item $extractedBin (Join-Path $InstallDir $BinName) -Force
  if (Test-Path (Join-Path $tmp 'scripts')) {
    $sd = Join-Path $SupportDir 'scripts'
    New-Item -ItemType Directory -Force -Path $sd | Out-Null
    Copy-Item (Join-Path $tmp 'scripts\*') $sd -Force -ErrorAction SilentlyContinue
  }

  # Add InstallDir to the user PATH if it is not already there.
  $userPath = [Environment]::GetEnvironmentVariable('Path', 'User')
  if (($userPath -split ';') -notcontains $InstallDir) {
    [Environment]::SetEnvironmentVariable('Path', "$userPath;$InstallDir", 'User')
    Write-Host "Added $InstallDir to your user PATH (restart your terminal to pick it up)."
  }

  Write-Host ""
  Write-Host "Installed $BinName to $InstallDir"
  Write-Host "Next steps (new terminal):"
  Write-Host "  1. From your project:  ai-indexer-mcp setup"
  Write-Host "  2. Check setup:        ai-indexer-mcp doctor --repo ."
  Write-Host "  3. Paid license:       ai-indexer-mcp license install <token>"
}
finally {
  Remove-Item -Recurse -Force $tmp -ErrorAction SilentlyContinue
}
