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

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

Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'

# Resolve-ExistingDirectory converts an MSBuild-supplied path into a stable
# absolute directory. Input is a path string, processing validates the directory,
# and output is the resolved full path used by the payload scanner.
function Resolve-ExistingDirectory {
    param([Parameter(Mandatory=$true)][string]$Path)
    if (-not (Test-Path -LiteralPath $Path -PathType Container)) {
        throw "Payload root does not exist: $Path"
    }
    return (Resolve-Path -LiteralPath $Path).Path
}

# Convert-ToResourceString escapes a relative path for safe C++ string literal
# emission. Input is a Windows relative path, processing escapes backslash and
# quotes, and output is a UTF-8 C++ literal body.
function Convert-ToResourceString {
    param([Parameter(Mandatory=$true)][string]$Text)
    $escapedText = $Text.Replace([string][char]92, ([string][char]92 + [string][char]92))
    return $escapedText.Replace('"', '\"')
}

$payloadRootPath = Resolve-ExistingDirectory -Path $PayloadRoot
$generatedPath = [System.IO.Path]::GetFullPath($GeneratedDirectory)
New-Item -ItemType Directory -Path $generatedPath -Force | Out-Null

$resourceHeaderPath = Join-Path $generatedPath 'PayloadResources.h'
$resourceRcPath = Join-Path $generatedPath 'PayloadResources.rc'

$files = Get-ChildItem -LiteralPath $payloadRootPath -Recurse -File -Force | Where-Object {
    $relative = $_.FullName.Substring($payloadRootPath.Length).TrimStart([char[]]@('\', '/'))
    $segments = $relative -split '[\\/]'
    if ($segments.Length -gt 0 -and ($segments[0] -ieq 'config' -or $segments[0] -ieq 'Style')) { return $false }
    if ($_.Extension -ieq '.pdb') { return $false }
    return $true
} | Sort-Object FullName

if ($files.Count -eq 0) {
    throw "No payload files were found under $payloadRootPath after exclusions."
}

$headerLines = New-Object System.Collections.Generic.List[string]
$rcLines = New-Object System.Collections.Generic.List[string]

$headerLines.Add('#pragma once')
$headerLines.Add('')
$headerLines.Add('// PayloadResources.h is generated by scripts/Generate-KswordSetupPayload.ps1.')
$headerLines.Add('// Each entry maps an embedded RCDATA resource to its installer-relative output path.')
$headerLines.Add('struct KswordSetupPayloadResourceEntry')
$headerLines.Add('{')
$headerLines.Add('    unsigned int resourceId;')
$headerLines.Add('    const wchar_t* relativePath;')
$headerLines.Add('    unsigned long long sourceSizeBytes;')
$headerLines.Add('};')
$headerLines.Add('')
$headerLines.Add('static constexpr KswordSetupPayloadResourceEntry kKswordSetupPayloadResources[] = {')

$rcLines.Add('// PayloadResources.rc is generated by scripts/Generate-KswordSetupPayload.ps1.')
$rcLines.Add('// It embeds the Release payload as RCDATA for the single-file installer.')

$id = 30000
foreach ($file in $files) {
    $relative = $file.FullName.Substring($payloadRootPath.Length).TrimStart([char[]]@('\', '/')).Replace('/', '\')
    $resourcePath = $file.FullName.Replace('\', '/').Replace('"', '""')
    $cppRelative = Convert-ToResourceString -Text $relative
    $headerLines.Add(('    {{ {0}u, L"{1}", {2}ull }},' -f $id, $cppRelative, ([UInt64]$file.Length)))
    $rcLines.Add(('{0} RCDATA "{1}"' -f $id, $resourcePath))
    $id++
}
$headerLines.Add('};')
$headerLines.Add('')
$headerLines.Add('static constexpr unsigned int kKswordSetupPayloadResourceCount =')
$headerLines.Add('    static_cast<unsigned int>(sizeof(kKswordSetupPayloadResources) / sizeof(kKswordSetupPayloadResources[0]));')

[System.IO.File]::WriteAllLines($resourceHeaderPath, $headerLines, [System.Text.UTF8Encoding]::new($false))
[System.IO.File]::WriteAllLines($resourceRcPath, $rcLines, [System.Text.UTF8Encoding]::new($false))

Write-Host "Generated KswordSetup payload resources: $($files.Count) files from $payloadRootPath"




