#Requires -Version 5.1
# Pure generator: collected values -> Windows Setup answer-file XML string.
# No WinForms dependency (unit-testable). Mirrors the legacy autounattend.xml but with
# ONE real local-admin account (no sm-bootstrap) and an embedded preconfig.json that the
# oobeSystem FirstLogonCommands write (in short base64 chunks) to
# C:\ProgramData\SilverMetal\preconfig.json. The base64 is carried in chunked echo
# commands rather than a single specialize RunSynchronousCommand/Path, because that Path
# is capped at ~259 chars and a full base64 blob overflows it -> "answer file is invalid".

function New-SmAnswerFile {
    param(
        [string]$DisplayName, [string]$Username, [string]$Password,
        [string]$ComputerName,
        [string]$InputLocale = '0809:00000809', [string]$SystemLocale = 'en-GB',
        [string]$UiLanguage = 'en-US', [string]$UserLocale = 'en-GB',
        [string]$Flavour, [bool]$BitLockerEnable = $false, [string]$BitLockerPin = ''
    )

    $pre = [ordered]@{
        schemaVersion = 1
        flavour       = $Flavour
        bitlocker     = [ordered]@{ enable = [bool]$BitLockerEnable; pin = $BitLockerPin }
        apps          = [ordered]@{ useFlavourDefaults = $true }
    }
    $preJson = ($pre | ConvertTo-Json -Depth 6 -Compress)
    $preB64  = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($preJson))

    function Esc([string]$s) { [Security.SecurityElement]::Escape($s) }
    # Escape ONLY the characters XML element content requires (& < >). Unlike
    # SecurityElement::Escape this leaves single/double quotes literal, so the
    # embedded command keeps a working FromBase64String('...') literal.
    function EscContent([string]$s) { $s.Replace('&','&amp;').Replace('<','&lt;').Replace('>','&gt;') }
    $dn = Esc $DisplayName; $un = Esc $Username; $pw = Esc $Password; $cn = Esc $ComputerName

    # Build the oobeSystem FirstLogonCommands. The preconfig base64 is split into short
    # (<=150 char) chunks, each appended to a temp file by its own `echo` command, then
    # the file is whitespace-stripped + base64-decoded into preconfig.json. This keeps
    # every single command line well under the unattend length limits.
    $preDir  = 'C:\ProgramData\SilverMetal'
    $preB64File = "$preDir\pre.b64"
    $preFile = "$preDir\preconfig.json"

    # Split base64 into chunks of at most 150 chars (base64 alphabet has no XML/cmd
    # metachars, so chunks are safe in `echo` and in XML once `>` is escaped).
    $chunkSize = 150
    $chunks = for ($i = 0; $i -lt $preB64.Length; $i += $chunkSize) {
        $preB64.Substring($i, [Math]::Min($chunkSize, $preB64.Length - $i))
    }

    $cmds = New-Object System.Collections.Generic.List[string]
    # 1. Create the target dir.
    $cmds.Add("cmd /c md ""$preDir"" 2>nul")
    # 2..N. Append each base64 chunk to the temp file.
    foreach ($c in $chunks) {
        $cmds.Add("cmd /c >>""$preB64File"" echo $c")
    }
    # N+1. Strip whitespace (chunks are newline-separated in the file) and decode.
    $cmds.Add("powershell -nop -c ""[IO.File]::WriteAllBytes('$preFile',[Convert]::FromBase64String(((gc '$preB64File' -raw) -replace '\s','')))""")
    # N+2. Clean up the temp file.
    $cmds.Add("cmd /c del ""$preB64File""")
    # N+3 (LAST). Launch the SilverMetal toolbox (run-once).
    $cmds.Add("cmd /c powershell -NoProfile -ExecutionPolicy Bypass -Command ""Start-Process -FilePath 'C:\Program Files\SilverOS\Welcome\SilverOS.Welcome.App.exe' -Verb RunAs""")

    $firstLogonSb = New-Object System.Text.StringBuilder
    $order = 0
    foreach ($cmd in $cmds) {
        $order++
        [void]$firstLogonSb.AppendLine("        <SynchronousCommand wcm:action=""add"" xmlns:wcm=""http://schemas.microsoft.com/WMIConfig/2002/State"">")
        [void]$firstLogonSb.AppendLine("          <Order>$order</Order>")
        [void]$firstLogonSb.AppendLine("          <CommandLine>$(EscContent $cmd)</CommandLine>")
        [void]$firstLogonSb.AppendLine("        </SynchronousCommand>")
    }
    $firstLogonCommands = $firstLogonSb.ToString().TrimEnd()

@"
<?xml version="1.0" encoding="utf-8"?>
<unattend xmlns="urn:schemas-microsoft-com:unattend">
  <settings pass="windowsPE">
    <component name="Microsoft-Windows-International-Core-WinPE" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
      <SetupUILanguage><UILanguage>$UiLanguage</UILanguage></SetupUILanguage>
      <InputLocale>$InputLocale</InputLocale><SystemLocale>$SystemLocale</SystemLocale>
      <UILanguage>$UiLanguage</UILanguage><UserLocale>$UserLocale</UserLocale>
    </component>
    <component name="Microsoft-Windows-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
      <DiskConfiguration>
        <WillShowUI>OnError</WillShowUI>
        <Disk wcm:action="add" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State">
          <DiskID>0</DiskID><WillWipeDisk>true</WillWipeDisk>
          <CreatePartitions>
            <CreatePartition wcm:action="add"><Order>1</Order><Type>EFI</Type><Size>300</Size></CreatePartition>
            <CreatePartition wcm:action="add"><Order>2</Order><Type>MSR</Type><Size>16</Size></CreatePartition>
            <CreatePartition wcm:action="add"><Order>3</Order><Type>Primary</Type><Extend>true</Extend></CreatePartition>
          </CreatePartitions>
          <ModifyPartitions>
            <ModifyPartition wcm:action="add"><Order>1</Order><PartitionID>1</PartitionID><Label>System</Label><Format>FAT32</Format></ModifyPartition>
            <ModifyPartition wcm:action="add"><Order>2</Order><PartitionID>2</PartitionID></ModifyPartition>
            <ModifyPartition wcm:action="add"><Order>3</Order><PartitionID>3</PartitionID><Label>Windows</Label><Format>NTFS</Format><Letter>C</Letter></ModifyPartition>
          </ModifyPartitions>
        </Disk>
      </DiskConfiguration>
      <ImageInstall><OSImage>
        <InstallTo><DiskID>0</DiskID><PartitionID>3</PartitionID></InstallTo>
        <InstallFrom><MetaData wcm:action="add" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State"><Key>/IMAGE/INDEX</Key><Value>1</Value></MetaData></InstallFrom>
      </OSImage></ImageInstall>
      <UserData><AcceptEula>true</AcceptEula></UserData>
    </component>
  </settings>
  <settings pass="oobeSystem">
    <component name="Microsoft-Windows-International-Core" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
      <InputLocale>$InputLocale</InputLocale><SystemLocale>$SystemLocale</SystemLocale>
      <UILanguage>$UiLanguage</UILanguage><UILanguageFallback>$UiLanguage</UILanguageFallback><UserLocale>$UserLocale</UserLocale>
    </component>
    <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
      <OOBE><HideEULAPage>true</HideEULAPage><HideOEMRegistrationScreen>true</HideOEMRegistrationScreen><HideOnlineAccountScreens>true</HideOnlineAccountScreens><HideLocalAccountScreen>true</HideLocalAccountScreen><HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE><ProtectYourPC>3</ProtectYourPC></OOBE>
      <UserAccounts><LocalAccounts>
        <LocalAccount wcm:action="add" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State">
          <Name>$un</Name><Group>Administrators</Group><DisplayName>$dn</DisplayName>
          <Password><Value>$pw</Value><PlainText>true</PlainText></Password>
        </LocalAccount>
      </LocalAccounts></UserAccounts>
      <AutoLogon><Enabled>true</Enabled><LogonCount>1</LogonCount><Username>$un</Username><Password><Value>$pw</Value><PlainText>true</PlainText></Password></AutoLogon>
      <ComputerName>$cn</ComputerName>
      <FirstLogonCommands>
$firstLogonCommands
      </FirstLogonCommands>
      <RegisteredOwner>SilverMetal</RegisteredOwner><RegisteredOrganization>SilverLABS</RegisteredOrganization>
    </component>
  </settings>
</unattend>
"@
}
