[CmdletBinding()]
param(
    [string]$Preset = "windows-msvc-default",
    [string]$Configuration = "Debug",
    [string]$Target = "PanoPainter",
    [string]$CMakeCommand = "cmake",
    [switch]$ReadinessOnly,
    [switch]$AndroidNativeChecks,
    [string[]]$PackageKinds = @(
        "windows-appx",
        "android-standard-apk",
        "android-quest-apk",
        "android-focus-apk",
        "apple-bundle",
        "linux-app",
        "webgl"
    )
)

$ErrorActionPreference = "Stop"
$started = Get-Date
$root = (Get-Location).Path

function Test-CommandAvailable {
    param([string]$Name)
    return [bool](Get-Command $Name -ErrorAction SilentlyContinue)
}

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 New-ArtifactCheck {
    param(
        [string]$Name,
        [string]$Path,
        [string]$PathType = "Any"
    )

    $exists = if ($PathType -eq "Container") {
        Test-Path -LiteralPath $Path -PathType Container
    } elseif ($PathType -eq "Leaf") {
        Test-Path -LiteralPath $Path -PathType Leaf
    } else {
        Test-Path -LiteralPath $Path
    }

    [ordered]@{
        name = $Name
        path = $Path
        pathType = $PathType
        exists = $exists
    }
}

function New-Prerequisite {
    param(
        [string]$Name,
        [bool]$Available,
        [string]$Detail
    )

    [ordered]@{
        name = $Name
        available = $Available
        detail = $Detail
    }
}

function New-PackageReadiness {
    param(
        [string]$Kind,
        [string]$Status,
        [string]$Reason,
        [object[]]$Prerequisites,
        [object[]]$Artifacts,
        [string]$ValidationCommand
    )

    [ordered]@{
        kind = $Kind
        status = $Status
        reason = $Reason
        debt = "DEBT-0011"
        validationCommand = $ValidationCommand
        prerequisites = $Prerequisites
        artifacts = $Artifacts
    }
}

function Resolve-PackageStatus {
    param(
        [bool]$RootCMakePackageTargetAvailable,
        [bool]$GateBlocked,
        [object[]]$Prerequisites
    )

    if ($GateBlocked) {
        return "blocked"
    }

    foreach ($prerequisite in $Prerequisites) {
        if ($prerequisite.name -eq "root-cmake-package-target") {
            continue
        }
        if (-not $prerequisite.available) {
            return "blocked"
        }
    }

    if ($RootCMakePackageTargetAvailable) {
        return "validated"
    }

    return "compile-only"
}

function Get-AndroidNativeCheckInfo {
    param(
        [string]$Kind,
        [bool]$AndroidNativeChecks,
        [object]$AndroidNativeValidation
    )

    $command = switch ($Kind) {
        "android-standard-apk" { "powershell -ExecutionPolicy Bypass -File scripts/automation/android-legacy-package-build.ps1 -Packages standard" }
        "android-quest-apk" { "powershell -ExecutionPolicy Bypass -File scripts/automation/android-legacy-package-build.ps1 -Packages quest -ConfigureOnly" }
        "android-focus-apk" { "powershell -ExecutionPolicy Bypass -File scripts/automation/android-legacy-package-build.ps1 -Packages focus -ConfigureOnly" }
        default { "" }
    }

    if (-not $AndroidNativeChecks) {
        return @{ Available = $true; Detail = "$command (not run)" }
    }

    if ($command.Length -eq 0) {
        return @{ Available = $false; Detail = "No Android native check plan for kind '$Kind'" }
    }

    $packages = switch ($Kind) {
        "android-standard-apk" { @("standard") }
        "android-quest-apk" { @("quest") }
        "android-focus-apk" { @("focus") }
        default { @() }
    }

    $result = $null
    foreach ($entry in $AndroidNativeValidation.results) {
        $hasAll = $true
        foreach ($pkg in $packages) {
            if (-not ($entry.packages -contains $pkg)) {
                $hasAll = $false
                break
            }
        }

        if ($hasAll) {
            $result = $entry
            break
        }
    }

    if (-not $result) {
        return @{ Available = $false; Detail = "$command (not executed)" }
    }

    if ($result.exitCode -ne 0) {
        return @{ Available = $false; Detail = "$command (exit $($result.exitCode))" }
    }

    return @{ Available = $true; Detail = $command }
}

function Get-AndroidNativeCheckPlan {
    param([string[]]$Kinds)

    $packages = @()
    if ($Kinds -contains "android-standard-apk") {
        $packages += [ordered]@{
            packages = @("standard")
            configureOnly = $false
        }
    }

    $configureOnlyPackages = @()
    if ($Kinds -contains "android-quest-apk") {
        $configureOnlyPackages += "quest"
    }
    if ($Kinds -contains "android-focus-apk") {
        $configureOnlyPackages += "focus"
    }
    if ($configureOnlyPackages.Count -gt 0) {
        $packages += [ordered]@{
            packages = $configureOnlyPackages
            configureOnly = $true
        }
    }

    return $packages
}

function Invoke-AndroidNativePackageChecks {
    param([string[]]$Kinds)

    $plans = @(Get-AndroidNativeCheckPlan -Kinds $Kinds)
    $results = @()
    $overallExitCode = 0

    foreach ($plan in $plans) {
        $arguments = @(
            "-ExecutionPolicy", "Bypass",
            "-File", (Join-Path $root "scripts/automation/android-legacy-package-build.ps1"),
            "-Packages", ($plan.packages -join ",")
        )
        if ($plan.configureOnly) {
            $arguments += "-ConfigureOnly"
        }

        $output = @(& powershell @arguments 2>&1)
        $exitCode = $LASTEXITCODE
        if ($exitCode -ne 0 -and $overallExitCode -eq 0) {
            $overallExitCode = $exitCode
        }

        $jsonLine = @($output | ForEach-Object { $_.ToString() } | Where-Object { $_.TrimStart().StartsWith("{") } | Select-Object -Last 1)
        $summary = $null
        if ($jsonLine.Count -gt 0) {
            try {
                $summary = $jsonLine[-1] | ConvertFrom-Json
            } catch {
                $summary = $null
            }
        }

        $results += [ordered]@{
            packages = $plan.packages
            configureOnly = [bool]$plan.configureOnly
            exitCode = $exitCode
            command = "powershell -ExecutionPolicy Bypass -File scripts\automation\android-legacy-package-build.ps1 -Packages $($plan.packages -join ',')$(if ($plan.configureOnly) { ' -ConfigureOnly' } else { '' })"
            summary = $summary
        }
    }

    [ordered]@{
        requested = $plans.Count -gt 0
        exitCode = $overallExitCode
        results = $results
    }
}

$PackageKinds = @(Expand-ArgumentList -Values $PackageKinds)

function Get-PackageReadiness {
    param([string[]]$Kinds)

    $readiness = @()
    foreach ($kind in $Kinds) {
        switch ($kind) {
            "windows-appx" {
                $wapproj = Join-Path $root "PanoPainterPackage/PanoPainterPackage.wapproj"
                $manifest = Join-Path $root "PanoPainterPackage/Package.appxmanifest"
                $appPackages = Join-Path $root "PanoPainterPackage/AppPackages"
                $prerequisites = @(
                    (New-Prerequisite -Name "legacy-wapproj" -Available (Test-Path -LiteralPath $wapproj -PathType Leaf) -Detail $wapproj),
                    (New-Prerequisite -Name "appx-manifest" -Available (Test-Path -LiteralPath $manifest -PathType Leaf) -Detail $manifest),
                    (New-Prerequisite -Name "makeappx" -Available (Test-CommandAvailable "makeappx") -Detail "Windows SDK packaging tool"),
                    (New-Prerequisite -Name "signtool" -Available (Test-CommandAvailable "signtool") -Detail "Windows SDK signing tool"),
                    (New-Prerequisite -Name "root-cmake-package-target" -Available $false -Detail "Not migrated yet")
                )
                $status = Resolve-PackageStatus -RootCMakePackageTargetAvailable $false -GateBlocked $true -Prerequisites $prerequisites
                $readiness += New-PackageReadiness `
                    -Kind $kind `
                    -Status $status `
                    -Reason "legacy-wapproj-present-but-root-cmake-package-target-missing" `
                    -ValidationCommand "msbuild PanoPainterPackage/PanoPainterPackage.wapproj /p:Configuration=$Configuration /p:Platform=x64" `
                    -Prerequisites $prerequisites `
                    -Artifacts @(
                        (New-ArtifactCheck -Name "app-packages" -Path $appPackages -PathType "Container")
                    )
            }
            "android-standard-apk" {
                $gradle = Join-Path $root "android/android/build.gradle"
                $manifest = Join-Path $root "android/android/src/main/AndroidManifest.xml"
                $apkDir = Join-Path $root "android/android/build/outputs/apk"
                $androidNativeCheck = Get-AndroidNativeCheckInfo -Kind $kind -AndroidNativeChecks $AndroidNativeChecks -AndroidNativeValidation $androidNativeValidation
                $prerequisites = @(
                    (New-Prerequisite -Name "gradle-build" -Available (Test-Path -LiteralPath $gradle -PathType Leaf) -Detail $gradle),
                    (New-Prerequisite -Name "android-manifest" -Available (Test-Path -LiteralPath $manifest -PathType Leaf) -Detail $manifest),
                    (New-Prerequisite -Name "gradle" -Available (Test-CommandAvailable "gradle") -Detail "Android package builder"),
                    (New-Prerequisite -Name "retained-native-cmake-check" -Available $androidNativeCheck.Available -Detail $androidNativeCheck.Detail),
                    (New-Prerequisite -Name "root-cmake-preset" -Available $true -Detail "android-arm64/android-x64"),
                    (New-Prerequisite -Name "root-cmake-package-target" -Available $false -Detail "Not migrated yet")
                )
                $status = Resolve-PackageStatus -RootCMakePackageTargetAvailable $false -GateBlocked $false -Prerequisites $prerequisites
                $readiness += New-PackageReadiness `
                    -Kind $kind `
                    -Status $status `
                    -Reason "legacy-gradle-package-not-consuming-root-cmake-targets" `
                    -ValidationCommand "gradle -p android/android assembleDebug" `
                    -Prerequisites $prerequisites `
                    -Artifacts @(
                        (New-ArtifactCheck -Name "apk-output" -Path $apkDir -PathType "Container")
                    )
            }
            "android-quest-apk" {
                $gradle = Join-Path $root "android/quest/build.gradle"
                $manifest = Join-Path $root "android/quest/src/main/AndroidManifest.xml"
                $apkDir = Join-Path $root "android/quest/build/outputs/apk"
                $androidNativeCheck = Get-AndroidNativeCheckInfo -Kind $kind -AndroidNativeChecks $AndroidNativeChecks -AndroidNativeValidation $androidNativeValidation
                $prerequisites = @(
                    (New-Prerequisite -Name "gradle-build" -Available (Test-Path -LiteralPath $gradle -PathType Leaf) -Detail $gradle),
                    (New-Prerequisite -Name "android-manifest" -Available (Test-Path -LiteralPath $manifest -PathType Leaf) -Detail $manifest),
                    (New-Prerequisite -Name "gradle" -Available (Test-CommandAvailable "gradle") -Detail "Android package builder"),
                    (New-Prerequisite -Name "retained-native-cmake-check" -Available $androidNativeCheck.Available -Detail $androidNativeCheck.Detail),
                    (New-Prerequisite -Name "root-cmake-preset" -Available $true -Detail "android-quest-arm64"),
                    (New-Prerequisite -Name "root-cmake-package-target" -Available $false -Detail "Not migrated yet")
                )
                $status = Resolve-PackageStatus -RootCMakePackageTargetAvailable $false -GateBlocked $false -Prerequisites $prerequisites
                $readiness += New-PackageReadiness `
                    -Kind $kind `
                    -Status $status `
                    -Reason "legacy-gradle-package-not-consuming-root-cmake-targets" `
                    -ValidationCommand "gradle -p android/quest assembleDebug" `
                    -Prerequisites $prerequisites `
                    -Artifacts @(
                        (New-ArtifactCheck -Name "apk-output" -Path $apkDir -PathType "Container")
                    )
            }
            "android-focus-apk" {
                $gradle = Join-Path $root "android/focus/build.gradle"
                $manifest = Join-Path $root "android/focus/src/main/AndroidManifest.xml"
                $apkDir = Join-Path $root "android/focus/build/outputs/apk"
                $androidNativeCheck = Get-AndroidNativeCheckInfo -Kind $kind -AndroidNativeChecks $AndroidNativeChecks -AndroidNativeValidation $androidNativeValidation
                $prerequisites = @(
                    (New-Prerequisite -Name "gradle-build" -Available (Test-Path -LiteralPath $gradle -PathType Leaf) -Detail $gradle),
                    (New-Prerequisite -Name "android-manifest" -Available (Test-Path -LiteralPath $manifest -PathType Leaf) -Detail $manifest),
                    (New-Prerequisite -Name "gradle" -Available (Test-CommandAvailable "gradle") -Detail "Android package builder"),
                    (New-Prerequisite -Name "retained-native-cmake-check" -Available $androidNativeCheck.Available -Detail $androidNativeCheck.Detail),
                    (New-Prerequisite -Name "root-cmake-preset" -Available $true -Detail "android-focus-arm64"),
                    (New-Prerequisite -Name "root-cmake-package-target" -Available $false -Detail "Not migrated yet")
                )
                $status = Resolve-PackageStatus -RootCMakePackageTargetAvailable $false -GateBlocked $false -Prerequisites $prerequisites
                $readiness += New-PackageReadiness `
                    -Kind $kind `
                    -Status $status `
                    -Reason "legacy-gradle-package-not-consuming-root-cmake-targets" `
                    -ValidationCommand "gradle -p android/focus assembleDebug" `
                    -Prerequisites $prerequisites `
                    -Artifacts @(
                        (New-ArtifactCheck -Name "apk-output" -Path $apkDir -PathType "Container")
                    )
            }
            "apple-bundle" {
                $xcodeProject = Join-Path $root "PanoPainter.xcodeproj/project.pbxproj"
                $bundleDir = Join-Path $root "out/package/apple"
                $prerequisites = @(
                    (New-Prerequisite -Name "legacy-xcode-project" -Available (Test-Path -LiteralPath $xcodeProject -PathType Leaf) -Detail $xcodeProject),
                    (New-Prerequisite -Name "xcodebuild" -Available (Test-CommandAvailable "xcodebuild") -Detail "Apple package builder"),
                    (New-Prerequisite -Name "root-cmake-preset" -Available $true -Detail "macos/ios-device/ios-simulator"),
                    (New-Prerequisite -Name "root-cmake-package-target" -Available $false -Detail "Not migrated yet")
                )
                $status = Resolve-PackageStatus -RootCMakePackageTargetAvailable $false -GateBlocked $true -Prerequisites $prerequisites
                $readiness += New-PackageReadiness `
                    -Kind $kind `
                    -Status $status `
                    -Reason "legacy-xcode-project-and-host-toolchain-not-aligned-with-root-cmake-package-target" `
                    -ValidationCommand "xcodebuild -project PanoPainter.xcodeproj -configuration $Configuration" `
                    -Prerequisites $prerequisites `
                    -Artifacts @(
                        (New-ArtifactCheck -Name "apple-package-output" -Path $bundleDir -PathType "Container")
                    )
            }
            "linux-app" {
                $linuxCmake = Join-Path $root "linux/CMakeLists.txt"
                $linuxBinary = Join-Path $root "out/package/linux/panopainter"
                $prerequisites = @(
                    (New-Prerequisite -Name "retained-linux-cmake" -Available (Test-Path -LiteralPath $linuxCmake -PathType Leaf) -Detail $linuxCmake),
                    (New-Prerequisite -Name "cmake" -Available (Test-CommandAvailable "cmake") -Detail "Linux retained app CMake configure/build tool"),
                    (New-Prerequisite -Name "retained-platform-cmake-baseline" -Available $true -Detail "python scripts/dev/check_retained_platform_cmake.py"),
                    (New-Prerequisite -Name "root-cmake-preset" -Available $true -Detail "linux-clang"),
                    (New-Prerequisite -Name "root-cmake-package-target" -Available $false -Detail "Not migrated yet")
                )
                $status = Resolve-PackageStatus -RootCMakePackageTargetAvailable $false -GateBlocked $false -Prerequisites $prerequisites
                $readiness += New-PackageReadiness `
                    -Kind $kind `
                    -Status $status `
                    -Reason "retained-linux-cmake-not-consuming-root-cmake-targets" `
                    -ValidationCommand "cmake -S linux -B out/package/linux-retained && cmake --build out/package/linux-retained --target panopainter" `
                    -Prerequisites $prerequisites `
                    -Artifacts @(
                        (New-ArtifactCheck -Name "linux-app-output" -Path $linuxBinary -PathType "Leaf")
                    )
            }
            "webgl" {
                $webglCmake = Join-Path $root "webgl/CMakeLists.txt"
                $webDir = Join-Path $root "out/package/webgl"
                $prerequisites = @(
                    (New-Prerequisite -Name "retained-webgl-cmake" -Available (Test-Path -LiteralPath $webglCmake -PathType Leaf) -Detail $webglCmake),
                    (New-Prerequisite -Name "emcc" -Available (Test-CommandAvailable "emcc") -Detail "Emscripten compiler"),
                    (New-Prerequisite -Name "emcmake" -Available (Test-CommandAvailable "emcmake") -Detail "Emscripten CMake wrapper"),
                    (New-Prerequisite -Name "retained-platform-cmake-baseline" -Available $true -Detail "python scripts/dev/check_retained_platform_cmake.py"),
                    (New-Prerequisite -Name "root-cmake-preset" -Available $true -Detail "emscripten"),
                    (New-Prerequisite -Name "root-cmake-package-target" -Available $false -Detail "Not migrated yet")
                )
                $status = Resolve-PackageStatus -RootCMakePackageTargetAvailable $false -GateBlocked $false -Prerequisites $prerequisites
                $readiness += New-PackageReadiness `
                    -Kind $kind `
                    -Status $status `
                    -Reason "retained-webgl-cmake-not-consuming-root-cmake-targets" `
                    -ValidationCommand "emcmake cmake -S webgl -B out/package/webgl-retained && cmake --build out/package/webgl-retained --target panopainter" `
                    -Prerequisites $prerequisites `
                    -Artifacts @(
                        (New-ArtifactCheck -Name "webgl-output" -Path $webDir -PathType "Container")
                    )
            }
        }
    }

    return $readiness
}

$androidNativeValidation = if ($AndroidNativeChecks) {
    Invoke-AndroidNativePackageChecks -Kinds $PackageKinds
} else {
    [ordered]@{
        requested = $false
        exitCode = 0
        results = @()
    }
}

if ($ReadinessOnly) {
    $elapsed = [int]((Get-Date) - $started).TotalMilliseconds
    [ordered]@{
        command = "package-smoke"
        preset = $Preset
        configuration = $Configuration
        target = $Target
        stage = "readiness"
        exitCode = 0
        elapsedMs = $elapsed
        androidNativeValidation = $androidNativeValidation
        packageReadiness = @(Get-PackageReadiness -Kinds $PackageKinds)
    } | ConvertTo-Json -Compress -Depth 8
    exit $androidNativeValidation.exitCode
}

& $CMakeCommand --build --preset $Preset --config $Configuration --target $Target
$buildExitCode = $LASTEXITCODE
if ($buildExitCode -ne 0) {
    $elapsed = [int]((Get-Date) - $started).TotalMilliseconds
    [ordered]@{
        command = "package-smoke"
        preset = $Preset
        configuration = $Configuration
        target = $Target
        stage = "build"
        cmakeCommand = $CMakeCommand
        exitCode = $buildExitCode
        elapsedMs = $elapsed
        androidNativeValidation = $androidNativeValidation
        packageReadiness = @(Get-PackageReadiness -Kinds $PackageKinds)
    } | ConvertTo-Json -Compress -Depth 8
    exit $buildExitCode
}

$binaryDir = Join-Path (Join-Path (Join-Path (Get-Location) "out/build/$Preset") $Configuration) "$Target.exe"
$targetDir = Split-Path -Parent $binaryDir
$dataDir = Join-Path $targetDir "data"
$curlDll = if ($Configuration -eq "Debug") { "libcurl_debug.dll" } else { "libcurl.dll" }
$checks = @(
    [ordered]@{ name = "executable"; path = $binaryDir; exists = Test-Path -LiteralPath $binaryDir -PathType Leaf },
    [ordered]@{ name = "data"; path = $dataDir; exists = Test-Path -LiteralPath $dataDir -PathType Container },
    [ordered]@{ name = "BugTrapU-x64.dll"; path = (Join-Path $targetDir "BugTrapU-x64.dll"); exists = Test-Path -LiteralPath (Join-Path $targetDir "BugTrapU-x64.dll") -PathType Leaf },
    [ordered]@{ name = $curlDll; path = (Join-Path $targetDir $curlDll); exists = Test-Path -LiteralPath (Join-Path $targetDir $curlDll) -PathType Leaf },
    [ordered]@{ name = "libyuv.dll"; path = (Join-Path $targetDir "libyuv.dll"); exists = Test-Path -LiteralPath (Join-Path $targetDir "libyuv.dll") -PathType Leaf },
    [ordered]@{ name = "libmp4v2.dll"; path = (Join-Path $targetDir "libmp4v2.dll"); exists = Test-Path -LiteralPath (Join-Path $targetDir "libmp4v2.dll") -PathType Leaf },
    [ordered]@{ name = "openh264-2.0.0-win64.dll"; path = (Join-Path $targetDir "openh264-2.0.0-win64.dll"); exists = Test-Path -LiteralPath (Join-Path $targetDir "openh264-2.0.0-win64.dll") -PathType Leaf },
    [ordered]@{ name = "openvr_api.dll"; path = (Join-Path $targetDir "openvr_api.dll"); exists = Test-Path -LiteralPath (Join-Path $targetDir "openvr_api.dll") -PathType Leaf }
)

$failed = @($checks | Where-Object { -not $_.exists })
$exitCode = if ($failed.Count -eq 0) { 0 } else { 2 }
if ($androidNativeValidation.exitCode -ne 0 -and $exitCode -eq 0) {
    $exitCode = $androidNativeValidation.exitCode
}
$elapsedMs = [int]((Get-Date) - $started).TotalMilliseconds

[ordered]@{
    command = "package-smoke"
    preset = $Preset
    configuration = $Configuration
    target = $Target
    cmakeCommand = $CMakeCommand
    exitCode = $exitCode
    elapsedMs = $elapsedMs
    checks = $checks
    androidNativeValidation = $androidNativeValidation
    packageReadiness = @(Get-PackageReadiness -Kinds $PackageKinds)
} | ConvertTo-Json -Compress -Depth 8

exit $exitCode
