# bootstrap-msys2.ps1
#
# Extracts the pinned MSYS2 base snapshot and installs the pinned package set
# from config/dependencies.lock.json. Everything lands under the local work
# root (default C:\nnffb) -- never a network drive, never a path with spaces.
#
#   powershell -ExecutionPolicy Bypass -File scripts\bootstrap-msys2.ps1
#
# Options:
#   -WorkRoot <path>   work root (default C:\nnffb)
#   -Force             re-extract MSYS2 even if a completed bootstrap exists
#
# Produces:
#   <WorkRoot>\msys64\                        MSYS2 UCRT64 environment
#   <WorkRoot>\manifests\msys2-package-inventory.txt
#   <WorkRoot>\manifests\bootstrap-manifest.json
#
# Requires: Windows 10 1803+ (built-in tar.exe for .tar.xz extraction).

[CmdletBinding()]
param(
    [string]$WorkRoot = 'C:\nnffb',
    [string]$DependencyLockPath,
    [switch]$Force
)

$ErrorActionPreference = 'Stop'
Set-StrictMode -Version Latest
Import-Module (Join-Path $PSScriptRoot 'BuildCommon.psm1') -Force

Assert-WorkRoot $WorkRoot
$paths = Get-BuildPaths $WorkRoot
New-Item -ItemType Directory -Force -Path $paths.downloads, $paths.manifests | Out-Null

$lock = Read-DependencyLock -Path $DependencyLockPath
$comp = Get-LockComponent $lock 'msys2-base'
$marker = Join-Path $paths.msysRoot '.nextnote-bootstrap'

Write-Host "`n=== 1. Download and verify MSYS2 base snapshot ($($comp.version)) ===" -ForegroundColor Cyan
$dl = Get-SingleResult -Context 'msys2-base download' -Results @(
    Invoke-PinnedDownload -Url $comp.url -OutFile (Join-Path $paths.downloads $comp.filename) `
        -Sha256 $comp.sha256 -AllowedHosts $comp.allowedHosts)
Write-Host ("{0}  sha256 verified{1}" -f $comp.filename, $(if ($dl.cached) { ' (cached)' } else { '' }))

Write-Host "`n=== 2. Extract ===" -ForegroundColor Cyan
$haveCompleted = (Test-Path $marker) -and ((Get-Content $marker -Raw -ErrorAction SilentlyContinue).Trim() -eq $comp.sha256)
if ($haveCompleted -and -not $Force) {
    Write-Host "Existing bootstrap matches pinned snapshot -- skipping extraction."
} else {
    if (Test-Path $paths.msysRoot) {
        if (-not $Force) {
            throw "$($paths.msysRoot) exists but is not a completed bootstrap of the pinned snapshot. Re-run with -Force to delete and re-extract."
        }
        Write-Host "Removing existing $($paths.msysRoot) (-Force)..."
        Remove-Item -Recurse -Force $paths.msysRoot
    }
    $tar = Get-Command tar.exe -ErrorAction SilentlyContinue
    if (-not $tar) { throw "tar.exe not found. Windows 10 1803+ provides it; it is required to extract the MSYS2 .tar.xz snapshot." }
    Write-Host "Extracting $($comp.filename) to $WorkRoot ..."
    & tar.exe -xf $dl.file -C $WorkRoot
    if ($LASTEXITCODE -ne 0) { throw "tar extraction failed (exit $LASTEXITCODE)." }
    if (-not (Test-Path (Join-Path $paths.msysRoot 'usr\bin\bash.exe'))) {
        throw "Extraction did not produce $($paths.msysRoot)\usr\bin\bash.exe -- snapshot layout unexpected."
    }
}

Write-Host "`n=== 3. Initialise MSYS2 ===" -ForegroundColor Cyan
# First login shell triggers MSYS2 post-install setup; run it standalone.
Invoke-MsysCommand -MsysRoot $paths.msysRoot -Command 'true' | Out-Null
Invoke-MsysCommand -MsysRoot $paths.msysRoot -Command 'pacman-key --init >/dev/null 2>&1; pacman-key --populate msys2 >/dev/null 2>&1; true' | Out-Null
Write-Host "MSYS2 initialised, pacman keyring populated."

Write-Host "`n=== 4. Install pinned package set ===" -ForegroundColor Cyan
$pkgs = @($comp.packages.install)
Write-Host ("Packages: {0}" -f ($pkgs -join ', '))
Invoke-MsysCommand -MsysRoot $paths.msysRoot -Command 'pacman -Sy --noconfirm' | Out-Null
Invoke-MsysCommand -MsysRoot $paths.msysRoot -Command ("pacman -S --noconfirm --needed " + ($pkgs -join ' ')) | Out-Null
Write-Host "Package installation complete."

Write-Host "`n=== 5. Record inventory ===" -ForegroundColor Cyan
$inventory = Invoke-MsysCommand -MsysRoot $paths.msysRoot -Command 'pacman -Q'
$invPath = Join-Path $paths.manifests 'msys2-package-inventory.txt'
[System.IO.File]::WriteAllLines($invPath, [string[]]$inventory)
Write-Host ("{0} packages recorded -> {1}" -f @($inventory).Count, $invPath)

$toolVersions = [ordered]@{}
foreach ($probe in @(
    @{ name = 'gcc';    cmd = 'gcc --version | head -n1' },
    @{ name = 'nasm';   cmd = 'nasm -v' },
    @{ name = 'make';   cmd = 'make --version | head -n1' },
    @{ name = 'cmake';  cmd = 'cmake --version | head -n1' },
    @{ name = 'ninja';  cmd = 'ninja --version' },
    @{ name = 'pkgconf';cmd = 'pkgconf --version' },
    @{ name = 'bash';   cmd = 'bash --version | head -n1' },
    @{ name = 'gpg';    cmd = 'gpg --version | head -n1' }
)) {
    $v = Invoke-MsysCommand -MsysRoot $paths.msysRoot -Command $probe.cmd -AllowFailure
    $toolVersions[$probe.name] = (@($v) -join ' ').Trim()
    Write-Host ("{0,-8} {1}" -f $probe.name, $toolVersions[$probe.name])
}
foreach ($required in 'gcc', 'nasm', 'make', 'cmake', 'gpg') {
    if (-not $toolVersions[$required]) { throw "Required tool '$required' is not functional after bootstrap." }
}

$manifest = [ordered]@{
    schemaVersion   = 1
    completedUtc    = (Get-Date).ToUniversalTime().ToString('o')
    machine         = $env:COMPUTERNAME
    os              = [System.Environment]::OSVersion.VersionString
    workRoot        = $WorkRoot
    snapshot        = [ordered]@{
        version = $comp.version; filename = $comp.filename; sha256 = $comp.sha256; cached = $dl.cached
    }
    packagesRequested = $pkgs
    packageInventory  = $invPath
    toolVersions      = $toolVersions
}
Write-JsonFile -Object $manifest -Path (Join-Path $paths.manifests 'bootstrap-manifest.json')

Set-Content -Path $marker -Value $comp.sha256 -NoNewline
Write-Host "`nBootstrap complete. Manifest: $(Join-Path $paths.manifests 'bootstrap-manifest.json')" -ForegroundColor Green
