[CmdletBinding()]
param(
    [switch]$Check
)

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

$repoRoot = Resolve-Path (Join-Path $PSScriptRoot "..")
$protoRoot = Join-Path $repoRoot "src/ZB.MOM.WW.MxGateway.Contracts/Protos"
$manifestPath = Join-Path $repoRoot "clients/proto/proto-inputs.json"
$descriptorPath = Join-Path $repoRoot "clients/proto/descriptors/mxaccessgw-client-v1.protoset"

function Resolve-Protoc {
    $pathCommand = Get-Command "protoc.exe" -ErrorAction SilentlyContinue
    if ($null -ne $pathCommand) {
        return $pathCommand.Source
    }

    $documentedPath = Join-Path $env:LOCALAPPDATA "Microsoft/WinGet/Packages/Google.Protobuf_Microsoft.Winget.Source_8wekyb3d8bbwe/bin/protoc.exe"
    if (Test-Path $documentedPath) {
        return $documentedPath
    }

    throw "Could not find protoc.exe. See docs/ToolchainLinks.md for the documented protobuf toolchain path."
}

function Ensure-Directory {
    param([string]$Path)

    if (-not (Test-Path $Path)) {
        New-Item -ItemType Directory -Path $Path | Out-Null
    }
}

function Compare-FileBytes {
    param(
        [string]$ExpectedPath,
        [string]$ActualPath
    )

    if (-not (Test-Path $ExpectedPath)) {
        return $false
    }

    $expected = [System.IO.File]::ReadAllBytes($ExpectedPath)
    $actual = [System.IO.File]::ReadAllBytes($ActualPath)
    if ($expected.Length -ne $actual.Length) {
        return $false
    }

    for ($index = 0; $index -lt $expected.Length; $index++) {
        if ($expected[$index] -ne $actual[$index]) {
            return $false
        }
    }

    return $true
}

$manifest = Get-Content -Raw $manifestPath | ConvertFrom-Json

Ensure-Directory (Split-Path $descriptorPath -Parent)
foreach ($output in $manifest.generatedOutputs.PSObject.Properties.Value) {
    Ensure-Directory (Join-Path $repoRoot $output)
}

$protoc = Resolve-Protoc
$outputPath = $descriptorPath
if ($Check) {
    $outputPath = Join-Path ([System.IO.Path]::GetTempPath()) ("mxaccessgw-client-v1-" + [System.Guid]::NewGuid().ToString("N") + ".protoset")
}

try {
    & $protoc `
        "--proto_path=$protoRoot" `
        "--include_imports" `
        "--include_source_info" `
        "--descriptor_set_out=$outputPath" `
        "mxaccess_gateway.proto" `
        "mxaccess_worker.proto" `
        "galaxy_repository.proto"

    if ($LASTEXITCODE -ne 0) {
        throw "protoc failed with exit code $LASTEXITCODE."
    }

    if ($Check -and -not (Compare-FileBytes -ExpectedPath $descriptorPath -ActualPath $outputPath)) {
        throw "Client proto descriptor is stale. Run scripts/publish-client-proto-inputs.ps1 and commit the updated descriptor."
    }
}
finally {
    if ($Check -and (Test-Path $outputPath)) {
        Remove-Item -LiteralPath $outputPath
    }
}
