param(
  [Parameter(Mandatory = $true)] [string] $BuildDir,
  [ValidateSet('ArtifactSigning', 'CertificateStore')] [string] $Provider = 'ArtifactSigning',
  [string] $MetadataFile,
  [string] $DlibPath,
  [string] $Thumbprint,
  [string] $TimestampUrl = 'http://timestamp.acs.microsoft.com'
)

$ErrorActionPreference = 'Stop'
$repo = Split-Path -Parent $PSScriptRoot
. (Join-Path $repo 'scripts/hash-utils.ps1')
$projectDeclaration = Get-Content -LiteralPath (Join-Path $repo 'CMakeLists.txt') -Raw
if ($projectDeclaration -notmatch 'project\(SmartCut64 VERSION ([0-9]+\.[0-9]+\.[0-9]+) LANGUAGES CXX\)') {
  throw 'Could not determine the SmartCut64 project version from CMakeLists.txt'
}
$version = $Matches[1]
$windowsPowerShell = Join-Path $PSHOME 'powershell.exe'
if (-not (Test-Path -LiteralPath $windowsPowerShell -PathType Leaf)) {
  throw "Could not locate the current Windows PowerShell executable: $windowsPowerShell"
}
if (-not $MetadataFile) { $MetadataFile = Join-Path $PSScriptRoot 'artifact-signing-metadata.json' }
$signtool = Get-ChildItem "${env:ProgramFiles(x86)}\Windows Kits\10\bin" -Recurse -Filter signtool.exe |
  Where-Object FullName -Match '\\x64\\signtool\.exe$' | Sort-Object FullName -Descending | Select-Object -First 1
if (-not $signtool) { throw 'Windows SDK signtool.exe was not found' }
$resolvedBuildDir = (Resolve-Path -LiteralPath $BuildDir).Path
if ($Provider -eq 'ArtifactSigning') {
  $MetadataFile = (Resolve-Path -LiteralPath $MetadataFile).Path
  if (-not $DlibPath) {
    $dlibRoots = @(
      "$env:ProgramFiles\Microsoft Artifact Signing Client Tools",
      "${env:ProgramFiles(x86)}\Microsoft Artifact Signing Client Tools",
      "$env:LOCALAPPDATA\Microsoft\ArtifactSigning",
      "$env:LOCALAPPDATA\Microsoft\MicrosoftArtifactSigningClientTools",
      (Join-Path $PSScriptRoot '..\build\tools')
    )
    $DlibPath = $dlibRoots | Where-Object { Test-Path -LiteralPath $_ } |
      ForEach-Object { Get-ChildItem -LiteralPath $_ -Recurse -Filter Azure.CodeSigning.Dlib.dll -ErrorAction SilentlyContinue } |
      Where-Object { $_.FullName -Match '\\x64\\Azure\.CodeSigning\.Dlib\.dll$' -or
                     $_.DirectoryName -eq "$env:LOCALAPPDATA\Microsoft\MicrosoftArtifactSigningClientTools" } |
      Select-Object -ExpandProperty FullName -First 1
  }
  if (-not $DlibPath -or -not (Test-Path -LiteralPath $DlibPath)) {
    throw 'Azure.CodeSigning.Dlib.dll was not found. Install Microsoft.Azure.ArtifactSigningClientTools or pass -DlibPath.'
  }
} else {
  if (-not $Thumbprint) { throw '-Thumbprint is required with -Provider CertificateStore' }
  $certificate = Get-ChildItem "Cert:\CurrentUser\My\$Thumbprint" -ErrorAction Stop
  if (-not $certificate.HasPrivateKey) { throw 'The signing certificate has no accessible private key' }
}

function Invoke-SignAndVerify([IO.FileInfo] $Target) {
  if ($Provider -eq 'ArtifactSigning') {
    & $signtool.FullName sign /v /fd SHA256 /tr $TimestampUrl /td SHA256 /dlib $DlibPath /dmdf $MetadataFile $Target.FullName
  } else {
    & $signtool.FullName sign /v /sha1 $Thumbprint /fd SHA256 /tr $TimestampUrl /td SHA256 $Target.FullName
  }
  if ($LASTEXITCODE -ne 0) { throw "Signing failed: $($Target.FullName)" }
  & $signtool.FullName verify /pa /all /v $Target.FullName
  if ($LASTEXITCODE -ne 0) { throw "Signature verification failed: $($Target.FullName)" }
}

$targetNames = @('smartcut-cli.exe', 'smartcut-gui.exe', 'smartcut-worker.exe')
$targets = @($targetNames | ForEach-Object {
  $path = Join-Path $resolvedBuildDir $_
  if (-not (Test-Path -LiteralPath $path -PathType Leaf)) { throw "Release binary was not found: $path" }
  Get-Item -LiteralPath $path
})
foreach ($target in $targets) { Invoke-SignAndVerify $target }
Push-Location $resolvedBuildDir
try { cpack -G ZIP; if ($LASTEXITCODE -ne 0) { throw 'Signed ZIP packaging failed' }; cpack -G NSIS; if ($LASTEXITCODE -ne 0) { throw 'Signed installer packaging failed' } } finally { Pop-Location }
& $windowsPowerShell -NoProfile -NonInteractive -ExecutionPolicy Bypass -File (Join-Path $PSScriptRoot 'rebuild-user-installer.ps1') -BuildDir $resolvedBuildDir
if ($LASTEXITCODE -ne 0) { throw 'Signed per-user installer rebuild failed' }
$installer = Get-Item -LiteralPath (Join-Path $resolvedBuildDir "SmartCut64-$version-win64.exe")
Invoke-SignAndVerify $installer
$package = Get-Item -LiteralPath (Join-Path $resolvedBuildDir "SmartCut64-$version-win64.zip")
$sourceBundle = Get-Item -LiteralPath (Join-Path $resolvedBuildDir "SmartCut64-$version-source.zip")
& $windowsPowerShell -NoProfile -NonInteractive -ExecutionPolicy Bypass -File (Join-Path $PSScriptRoot 'package-install-test.ps1') -Package $package.FullName
if ($LASTEXITCODE -ne 0) { throw 'Signed package install validation failed' }
& $windowsPowerShell -NoProfile -NonInteractive -ExecutionPolicy Bypass -File (Join-Path $PSScriptRoot 'installer-install-test.ps1') -Installer $installer.FullName
if ($LASTEXITCODE -ne 0) { throw 'Signed installer install/uninstall validation failed' }
$checksumFile = Join-Path $resolvedBuildDir "SmartCut64-$version-SHA256SUMS.txt"
$checksumLines = @($package, $installer, $sourceBundle) | ForEach-Object {
  $hash = (Get-SmartCutSha256 -LiteralPath $_.FullName).ToLowerInvariant()
  "$hash  $($_.Name)"
}
[IO.File]::WriteAllLines($checksumFile, $checksumLines, [Text.Encoding]::ASCII)
Write-Host "Signed and verified $($targets.Count) binaries and the installer with $Provider"
Write-Host "Signed release checksums refreshed: $checksumFile"
