[CmdletBinding()]
param(
    [string[]]$Presets = @("android-arm64", "android-x64", "android-quest-arm64", "android-focus-arm64"),
    [string[]]$Targets = @(
        "pp_foundation",
        "pp_assets",
        "pp_paint",
        "pp_document",
        "pp_renderer_api",
        "pp_renderer_gl",
        "pp_paint_renderer",
        "pp_ui_core",
        "pp_platform_api",
        "pp_app_core",
        "pano_cli",
        "pp_foundation_binary_stream_tests",
        "pp_foundation_event_tests",
        "pp_foundation_log_tests",
        "pp_foundation_parse_tests",
        "pp_foundation_task_queue_tests",
        "pp_foundation_trace_tests",
        "pp_foundation_task_queue_stress_tests",
        "pp_assets_brush_package_tests",
        "pp_assets_image_format_tests",
        "pp_assets_image_metadata_tests",
        "pp_assets_image_pixels_tests",
        "pp_assets_ppi_header_tests",
        "pp_assets_settings_document_tests",
        "pp_paint_brush_tests",
        "pp_paint_blend_tests",
        "pp_paint_stroke_tests",
        "pp_paint_stroke_script_tests",
        "pp_document_tests",
        "pp_document_ppi_import_tests",
        "pp_document_ppi_export_tests",
        "pp_renderer_api_tests",
        "pp_renderer_gl_capabilities_tests",
        "pp_renderer_gl_command_plan_tests",
        "pp_paint_renderer_compositor_tests",
        "pp_paint_renderer_stroke_execution_tests",
        "pp_renderer_gl_gpu_readback_tests",
        "pp_platform_api_tests",
        "pp_ui_core_color_tests",
        "pp_ui_core_layout_value_tests",
        "pp_ui_core_layout_xml_tests",
        "pp_ui_core_node_lifetime_tests",
        "pp_ui_core_overlay_lifetime_tests",
        "pp_app_core_about_menu_tests",
        "pp_app_core_app_dialog_tests",
        "pp_app_core_app_preferences_tests",
        "pp_app_core_app_frame_tests",
        "pp_app_core_app_thread_tests",
        "pp_app_core_app_input_tests",
        "pp_app_core_app_shutdown_tests",
        "pp_app_core_app_startup_tests",
        "pp_app_core_app_status_tests",
        "pp_app_core_app_thread_stress_tests",
        "pp_app_core_command_convert_tests",
        "pp_app_core_brush_package_export_tests",
        "pp_app_core_brush_package_import_tests",
        "pp_app_core_brush_ui_tests",
        "pp_app_core_canvas_hotkey_tests",
        "pp_app_core_canvas_tool_ui_tests",
        "pp_app_core_canvas_view_tests",
        "pp_app_core_document_animation_tests",
        "pp_app_core_document_canvas_tests",
        "pp_app_core_document_cloud_tests",
        "pp_app_core_document_export_tests",
        "pp_app_core_document_import_tests",
        "pp_app_core_document_layer_tests",
        "pp_app_core_document_platform_io_tests",
        "pp_app_core_document_recording_tests",
        "pp_app_core_document_resize_tests",
        "pp_app_core_document_route_tests",
        "pp_app_core_document_sharing_tests",
        "pp_app_core_document_session_tests",
        "pp_app_core_file_menu_tests",
        "pp_app_core_grid_ui_tests",
        "pp_app_core_history_ui_tests",
        "pp_app_core_main_toolbar_tests",
        "pp_app_core_quick_ui_tests",
        "pp_app_core_tools_menu_tests"
    ),
    [switch]$Quiet,
    [string]$LogDir = "out/logs/platform-build",
    [int]$FailureTailLines = 0
)

$ErrorActionPreference = "Stop"

function Expand-ArgumentList {
    param([string[]]$Values)

    $expanded = @()
    foreach ($value in $Values) {
        foreach ($part in ($value -split ",")) {
            $trimmed = $part.Trim()
            if ($trimmed.Length -gt 0) {
                $expanded += $trimmed
            }
        }
    }
    return $expanded
}

function Limit-LogSlug {
    param(
        [string]$Value,
        [int]$MaxLength = 96
    )

    if ($Value.Length -le $MaxLength) {
        return $Value
    }
    return $Value.Substring(0, $MaxLength)
}

function Invoke-LoggedCommand {
    param(
        [string]$Command,
        [string[]]$Arguments,
        [string]$LogPath,
        [int]$FailureTailLines
    )

    $started = Get-Date
    $exitCode = 0
    $restoreNativeCommandPreference = $false
    if (Get-Variable -Name PSNativeCommandUseErrorActionPreference -ErrorAction SilentlyContinue) {
        $previousNativeCommandPreference = $PSNativeCommandUseErrorActionPreference
        $PSNativeCommandUseErrorActionPreference = $false
        $restoreNativeCommandPreference = $true
    }
    try {
        & $Command @Arguments *> $LogPath
        $exitCode = $LASTEXITCODE
        if ($null -eq $exitCode) {
            $exitCode = 0
        }
    }
    catch {
        $_ | Out-File -LiteralPath $LogPath -Append -Encoding utf8
        $exitCode = 1
    }
    finally {
        if ($restoreNativeCommandPreference) {
            $PSNativeCommandUseErrorActionPreference = $previousNativeCommandPreference
        }
    }

    $result = [ordered]@{
        exitCode = $exitCode
        elapsedMs = [int]((Get-Date) - $started).TotalMilliseconds
        log = $LogPath
    }

    if ($exitCode -ne 0 -and $FailureTailLines -gt 0 -and (Test-Path -LiteralPath $LogPath)) {
        $result.failureTail = @(Get-Content -LiteralPath $LogPath -Tail $FailureTailLines | ForEach-Object { [string]$_ })
    }

    return $result
}

function Get-VcpkgRoot {
    $candidates = @()
    if ($env:VCPKG_ROOT) {
        $candidates += $env:VCPKG_ROOT
    }

    $programFiles = @($env:ProgramFiles, ${env:ProgramFiles(x86)}) | Where-Object { $_ }
    $vsYears = @("2026", "2022")
    $vsEditions = @("Community", "Professional", "Enterprise", "BuildTools", "Preview")
    foreach ($root in $programFiles) {
        foreach ($year in $vsYears) {
            foreach ($edition in $vsEditions) {
                $candidates += (Join-Path $root "Microsoft Visual Studio\$year\$edition\VC\vcpkg")
            }
        }
    }

    foreach ($candidate in $candidates) {
        if ($candidate -and (Test-Path -LiteralPath (Join-Path $candidate "vcpkg.exe") -PathType Leaf)) {
            return (Resolve-Path -LiteralPath $candidate).Path
        }
    }

    throw "VCPKG_ROOT was not set and no Visual Studio bundled vcpkg root was found."
}

function Set-VcpkgRootEnvironment {
    $vcpkgRoot = Get-VcpkgRoot
    $env:VCPKG_ROOT = $vcpkgRoot
    return [ordered]@{
        vcpkgRoot = $vcpkgRoot
        vcpkgCommand = Join-Path $vcpkgRoot "vcpkg.exe"
    }
}

$Presets = @(Expand-ArgumentList -Values $Presets)
$Targets = @(Expand-ArgumentList -Values $Targets)

$cmakeCommand = "cmake"
$androidToolchain = $null
$vcpkgToolchain = $null
if ($Presets | Where-Object { $_ -like "*vcpkg*" }) {
    $vcpkgToolchain = Set-VcpkgRootEnvironment
}
if ($Presets | Where-Object { $_ -like "android-*" }) {
    . "$PSScriptRoot\android-sdk-env.ps1"
    $androidToolchain = Set-AndroidSdkToolchainEnvironment
    $cmakeCommand = $androidToolchain.cmakeCommand
}

$started = Get-Date
$results = @()
$overallExitCode = 0
$runId = Get-Date -Format "yyyyMMdd-HHmmss"

if ($Quiet) {
    New-Item -ItemType Directory -Force -Path $LogDir | Out-Null
}

foreach ($preset in $Presets) {
    $presetCmakeCommand = $cmakeCommand
    if ($androidToolchain -and $preset -notlike "android-*") {
        $presetCmakeCommand = "cmake"
    }

    $configureExitCode = 0
    $configureLog = $null
    if ($Quiet) {
        $configureLog = Join-Path -Path $LogDir -ChildPath ("{0}-configure-{1}.log" -f $runId, (Limit-LogSlug (($preset -replace "[^A-Za-z0-9_.-]", "_"))))
        $configureResult = Invoke-LoggedCommand `
            -Command $presetCmakeCommand `
            -Arguments @("--preset", $preset) `
            -LogPath $configureLog `
            -FailureTailLines $FailureTailLines
        $configureExitCode = $configureResult.exitCode
    }
    else {
        & $presetCmakeCommand --preset $preset
        $configureExitCode = $LASTEXITCODE
    }
    if ($configureExitCode -ne 0) {
        $overallExitCode = $configureExitCode
        $result = [ordered]@{
            preset = $preset
            stage = "configure"
            exitCode = $configureExitCode
        }
        if ($Quiet) {
            $result.log = $configureLog
            if ($configureResult.Contains("failureTail")) {
                $result.failureTail = $configureResult.failureTail
            }
        }
        $results += $result
        continue
    }

    $buildArgs = @("--build", "--preset", $preset)
    foreach ($target in $Targets) {
        $buildArgs += @("--target", $target)
    }

    $buildExitCode = 0
    $buildLog = $null
    if ($Quiet) {
        $safeTargets = Limit-LogSlug (($Targets -join "_") -replace "[^A-Za-z0-9_.-]", "_")
        $buildLog = Join-Path -Path $LogDir -ChildPath ("{0}-build-{1}-{2}.log" -f $runId, ($preset -replace "[^A-Za-z0-9_.-]", "_"), $safeTargets)
        $buildResult = Invoke-LoggedCommand `
            -Command $presetCmakeCommand `
            -Arguments $buildArgs `
            -LogPath $buildLog `
            -FailureTailLines $FailureTailLines
        $buildExitCode = $buildResult.exitCode
    }
    else {
        & $presetCmakeCommand @buildArgs
        $buildExitCode = $LASTEXITCODE
    }
    if ($buildExitCode -ne 0 -and $overallExitCode -eq 0) {
        $overallExitCode = $buildExitCode
    }

    $result = [ordered]@{
        preset = $preset
        stage = "build"
        targets = $Targets
        exitCode = $buildExitCode
    }
    if ($Quiet) {
        $result.log = $buildLog
        if ($buildResult.Contains("failureTail")) {
            $result.failureTail = $buildResult.failureTail
        }
    }
    $results += $result
}

$elapsed = [int]((Get-Date) - $started).TotalMilliseconds
[ordered]@{
    command = "platform-build"
    exitCode = $overallExitCode
    elapsedMs = $elapsed
    androidToolchain = $androidToolchain
    vcpkgToolchain = $vcpkgToolchain
    results = $results
} | ConvertTo-Json -Compress -Depth 6

exit $overallExitCode
