# Send-PxeStatus.ps1
# Posts a coarse-grained progress update to the PXE webapp's /imaging/status
# endpoint. Never blocks imaging on a failed push (try/catch with no rethrow).
# Air-gapped LAN; no auth - the webapp endpoint is CSRF-exempt for machine
# clients (see services/csrf.py).

function Send-PxeStatus {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [string]$Stage,
        [int]$StageIndex = 0,
        [int]$StageTotal = 0,
        [ValidateSet('in_progress','succeeded','failed')]
        [string]$Status = 'in_progress',
        [string]$Error_ = '',
        [string[]]$LogLines = @(),
        # Intune device ID (AAD/Entra device GUID from `dsregcmd /status`).
        # Only available post-AAD-join; pass it from Monitor-IntuneProgress
        # once captured. The dashboard renders a QR of this value.
        [string]$IntuneDeviceId = '',
        [string]$PxeServer = '10.9.100.1',
        [int]$Port = 9009,
        [int]$TimeoutSec = 5
    )

    # Get serial early; if WMI fails we still want to push under a best-effort id.
    $serial = $null
    try {
        $serial = (Get-CimInstance -ClassName Win32_BIOS -ErrorAction Stop).SerialNumber
    } catch {
        try { $serial = (Get-WmiObject -Class Win32_BIOS -ErrorAction Stop).SerialNumber } catch { }
    }
    if ([string]::IsNullOrWhiteSpace($serial)) { $serial = $env:COMPUTERNAME }
    $serial = ($serial -as [string]).Trim()

    # MAC of the first up wired adapter (best-effort; PXE servers see this MAC in DHCP).
    $mac = $null
    try {
        $nic = Get-NetAdapter -Physical | Where-Object { $_.Status -eq 'Up' -and $_.MediaType -eq '802.3' } | Select-Object -First 1
        if ($nic) { $mac = $nic.MacAddress -replace '-', ':' }
    } catch { }

    # Enrollment context files (present after startnet.cmd stages them).
    $pctype = ''
    $machno = ''
    if (Test-Path 'C:\Enrollment\pc-type.txt')        { $pctype = (Get-Content 'C:\Enrollment\pc-type.txt' -ErrorAction SilentlyContinue | Select-Object -First 1).Trim() }
    if (Test-Path 'C:\Enrollment\machine-number.txt') { $machno = (Get-Content 'C:\Enrollment\machine-number.txt' -ErrorAction SilentlyContinue | Select-Object -First 1).Trim() }

    $payload = @{
        serial          = $serial
        mac             = $mac
        hostname_target = $env:COMPUTERNAME
        pctype          = $pctype
        machinenumber   = $machno
        current_stage   = $Stage
        stage_index     = $StageIndex
        stage_total     = $StageTotal
        status          = $Status
    }
    if ($Error_)         { $payload.error = $Error_ }
    if ($LogLines)       { $payload.log_lines = $LogLines }
    if ($IntuneDeviceId) { $payload.intune_device_id = $IntuneDeviceId }

    $body = $payload | ConvertTo-Json -Compress
    $uri  = "http://${PxeServer}:${Port}/imaging/status"

    # Always log the attempt to C:\Logs\send-pxe-status.log so the operator
    # can correlate dashboard state against actual outbound POSTs. Logs both
    # success (one line per fired stage) and failure (with exception).
    $logFile = 'C:\Logs\send-pxe-status.log'
    try {
        if (-not (Test-Path 'C:\Logs')) { New-Item -ItemType Directory -Path 'C:\Logs' -Force | Out-Null }
    } catch { }

    try {
        $resp = Invoke-WebRequest -Uri $uri -Method POST `
            -Body $body -ContentType 'application/json' `
            -UseBasicParsing -TimeoutSec $TimeoutSec `
            -ErrorAction Stop
        try {
            "$(Get-Date -Format s) OK  idx=$StageIndex/$StageTotal  status=$Status  http=$($resp.StatusCode)  stage='$Stage'" |
                Out-File -FilePath $logFile -Append -Encoding utf8
        } catch { }
    } catch {
        try {
            "$(Get-Date -Format s) ERR idx=$StageIndex/$StageTotal  status=$Status  uri=$uri  stage='$Stage'  err=$($_.Exception.Message)" |
                Out-File -FilePath $logFile -Append -Encoding utf8
        } catch { }
        # Never block imaging on a failed status push.
    }
}
