<#
.SYNOPSIS
    Windows/x86 Worker CI stage — runs ON windev (10.100.0.48), invoked over SSH by
    scripts/ci/run-windev-ci.sh at the exact SHA under test. Restores the x86/net48
    Worker test tier that the removed `windows` CI job used to cover (TST-25).

.DESCRIPTION
    The Linux `windows-x86` / nightly CI jobs cannot build the x86/net48 Worker, so they
    ssh here and run this script inside the isolated CI clone C:\build\mxaccessgw-ci.

    The script is deliberately self-contained and versioned with the code under test: the
    SSH bootstrap only fetches + checks out the SHA (enough to load *this* file), then this
    script re-fetches and re-checks-out $Sha INSIDE the worktree lock so the checkout+build
    are fully serialized against a concurrent run and can never stomp each other's tree.

    Modes (cumulative):
      build  x86 Worker build only (net48/CS0246/x86 compile guard — always fast).
      test   build + Worker.Tests (x86). The per-push default.
      live   test + the live-MXAccess smoke (MXGATEWAY_RUN_LIVE_MXACCESS_TESTS=1) and a full
             slnx build (surfaces Windows-only analyzer diagnostics, e.g. xUnit1030). Nightly.

    Runs under Windows PowerShell 5.1 (`powershell.exe`), so it avoids PS7-only syntax and
    checks $LASTEXITCODE after every native command rather than relying on stderr-as-error
    (git writes progress to stderr — the known windev gotcha).

    Exits nonzero on the first failure so the SSH exit code propagates to the CI job.

.PARAMETER Sha
    The commit SHA under test. HEAD is force-checked-out to it and verified.

.PARAMETER Mode
    build | test | live.

.PARAMETER RepoRoot
    The CI clone root. Defaults to C:\build\mxaccessgw-ci.
#>
[CmdletBinding()]
param(
    [Parameter(Mandatory = $true)][string]$Sha,
    [Parameter(Mandatory = $true)][ValidateSet('build', 'test', 'live')][string]$Mode,
    [string]$RepoRoot = 'C:\build\mxaccessgw-ci'
)

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

$lockDir = "$RepoRoot.lock"
$logFile = Join-Path $RepoRoot 'ci.log'
$lockTimeout = [TimeSpan]::FromMinutes(20)

function Write-Log {
    param([string]$Message)
    $line = ('[{0}] {1}' -f (Get-Date -Format 'yyyy-MM-dd HH:mm:ss'), $Message)
    Write-Host $line
    # Best-effort file log for the "is the tier down?" diagnosis in docs/GatewayTesting.md.
    try { Add-Content -Path $logFile -Value $line -ErrorAction SilentlyContinue } catch { }
}

# Run a native command and throw on nonzero exit. Native stderr (git progress) does NOT
# set $LASTEXITCODE, so it is not treated as failure — only a real nonzero exit is.
function Invoke-Native {
    param([Parameter(Mandatory = $true)][string]$What, [Parameter(Mandatory = $true)][scriptblock]$Command)
    Write-Log "RUN: $What"
    & $Command
    if ($LASTEXITCODE -ne 0) {
        throw "$What failed with exit code $LASTEXITCODE"
    }
}

# --- acquire the worktree lock (mkdir is atomic; retry until timeout) ---
# run-windev-ci.sh's bootstrap already holds this lock around its pre-hand-off fetch/checkout
# (MXGW_CI_LOCK_HELD=1) so that stage can't race a concurrent run; re-use it rather than
# re-acquire (and leave releasing to the bootstrap). A standalone/manual run (degraded mode)
# has no such env and self-locks here as before.
$deadline = (Get-Date).Add($lockTimeout)
$haveLock = $false
if ($env:MXGW_CI_LOCK_HELD -eq '1') {
    Write-Log "Worktree lock already held by bootstrap (mode=$Mode sha=$Sha)"
}
else {
    Write-Log "Acquiring worktree lock $lockDir (mode=$Mode sha=$Sha)"
    while (-not $haveLock) {
        try {
            New-Item -Path $lockDir -ItemType Directory -ErrorAction Stop | Out-Null
            $haveLock = $true
        }
        catch {
            if ((Get-Date) -ge $deadline) {
                throw "Timed out after $($lockTimeout.TotalMinutes) min waiting for worktree lock $lockDir. A stuck run may have left it; if no CI job is active, remove it by hand."
            }
            Start-Sleep -Seconds 10
        }
    }
}

try {
    Push-Location $RepoRoot
    try {
        # Re-fetch + re-checkout under the lock so a concurrent run's bootstrap checkout
        # (done before we held the lock) cannot leave us on the wrong tree.
        Invoke-Native 'git fetch origin' { git fetch --prune origin }
        Invoke-Native "git checkout --force $Sha" { git checkout --force --detach $Sha }
        # Drop any stray tracked/untracked residue from a prior run so the build is clean.
        Invoke-Native 'git reset --hard' { git reset --hard $Sha }
        Invoke-Native 'git clean -fdx (build outputs)' { git clean -fdx -e ci.log }

        $head = (& git rev-parse HEAD).Trim()
        if ($head -ne $Sha) {
            throw "Worktree HEAD $head does not match requested SHA $Sha after checkout."
        }
        Write-Log "Worktree at $head"

        $workerProj = 'src/ZB.MOM.WW.MxGateway.Worker/ZB.MOM.WW.MxGateway.Worker.csproj'
        $workerTests = 'src/ZB.MOM.WW.MxGateway.Worker.Tests/ZB.MOM.WW.MxGateway.Worker.Tests.csproj'
        $integrationTests = 'src/ZB.MOM.WW.MxGateway.IntegrationTests/ZB.MOM.WW.MxGateway.IntegrationTests.csproj'

        # build: always. The x86/net48 compile is the floor guard (catches CS0246 on
        # unregenerated Generated/, x86-only breaks) even when the test step is demoted.
        Invoke-Native 'x86 Worker build' { dotnet build $workerProj -c Release -p:Platform=x86 }

        if ($Mode -eq 'test' -or $Mode -eq 'live') {
            Invoke-Native 'x86 Worker.Tests' { dotnet test $workerTests -c Release -p:Platform=x86 }
        }

        if ($Mode -eq 'live') {
            # Full-solution build surfaces Windows-only analyzer diagnostics (xUnit1030 etc.)
            # that never fire on the macOS/Linux NonWindows build.
            Invoke-Native 'full slnx build' { dotnet build src/ZB.MOM.WW.MxGateway.slnx -c Release }

            $env:MXGATEWAY_RUN_LIVE_MXACCESS_TESTS = '1'
            try {
                Invoke-Native 'live-MXAccess smoke' {
                    dotnet test $integrationTests -c Release --filter 'FullyQualifiedName~WorkerLiveMxAccessSmokeTests'
                }
            }
            finally {
                Remove-Item Env:\MXGATEWAY_RUN_LIVE_MXACCESS_TESTS -ErrorAction SilentlyContinue
            }
        }

        Write-Log "SUCCESS mode=$Mode sha=$Sha"
    }
    finally {
        Pop-Location
    }
}
catch {
    Write-Log "FAILURE mode=$Mode sha=$Sha : $($_.Exception.Message)"
    throw
}
finally {
    if ($haveLock) {
        Remove-Item -Path $lockDir -Recurse -Force -ErrorAction SilentlyContinue
        Write-Log "Released worktree lock $lockDir"
    }
}
