param(
  [Parameter(Mandatory = $true)]
  [string]$SourceDir,

  [Parameter(Mandatory = $true)]
  [string]$OutputPath
)

$ErrorActionPreference = "Stop"

function ConvertTo-NsisString {
  param([string]$Value)

  return $Value.Replace('$', '$$').Replace('"', '$\"')
}

$sourceRoot = (Resolve-Path -LiteralPath $SourceDir).Path.TrimEnd('\')
$sourcePrefix = "$sourceRoot\"
$files = @(
  Get-ChildItem -LiteralPath $sourceRoot -Recurse -File -Force |
    Sort-Object FullName
)

if ($files.Count -eq 0) {
  throw "No files were found in NSIS application source directory: $sourceRoot"
}

[long]$totalBytes = ($files | Measure-Object -Property Length -Sum).Sum
$lines = [System.Collections.Generic.List[string]]::new()
$lines.Add("!define APP_COPY_TOTAL_BYTES `"$totalBytes`"")
$lines.Add("!macro copyApplicationFilesWithProgress")

$lastRelativeDirectory = $null
foreach ($file in $files) {
  $relativePath = $file.FullName.Substring($sourcePrefix.Length)
  $relativeDirectory = Split-Path -Parent $relativePath
  $escapedRelativePath = ConvertTo-NsisString $relativePath
  $escapedSourcePath = ConvertTo-NsisString $file.FullName
  $escapedFileName = ConvertTo-NsisString $file.Name

  if ($relativeDirectory -ne $lastRelativeDirectory) {
    if ([string]::IsNullOrEmpty($relativeDirectory)) {
      $lines.Add('  SetOutPath "$INSTDIR"')
    } else {
      $escapedDirectory = ConvertTo-NsisString $relativeDirectory
      $lines.Add("  SetOutPath `"`$INSTDIR\$escapedDirectory`"")
    }
    $lastRelativeDirectory = $relativeDirectory
  }

  $lines.Add("  File `"/oname=$escapedFileName`" `"$escapedSourcePath`"")
  $lines.Add(
    "  !insertmacro progressCopyFile `"$($file.Length)`" `"$escapedRelativePath`""
  )
}

$lines.Add("!macroend")

$encoding = [System.Text.UTF8Encoding]::new($false)
[System.IO.File]::WriteAllLines($OutputPath, $lines, $encoding)

Write-Host "Generated NSIS commands for $($files.Count) files ($totalBytes bytes)."
