[CmdletBinding()]
param(
  [string]$Package = "examples/showcase/windows_wgpu",
  [string]$AppName = "",
  [string]$DistDir = "dist\windows",
  [switch]$NoBuild,
  [string]$Msys2Root = "C:\msys64",
  [string]$WgpuNativeRoot = "",
  [string]$Version = "0.1.0",
  [string]$BuildNumber = "1"
)

$ErrorActionPreference = "Stop"

function Require-Path {
  param(
    [string]$PathValue,
    [string]$Message
  )

  if (-not (Test-Path -LiteralPath $PathValue)) {
    throw $Message
  }
}

function Convert-PackagePath {
  param([string]$Value)
  return ($Value -replace '/', '\')
}

function Write-Utf8NoBom {
  param(
    [string]$PathValue,
    [string]$Value
  )

  $encoding = New-Object System.Text.UTF8Encoding($false)
  [System.IO.File]::WriteAllText($PathValue, $Value, $encoding)
}

$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$repoRoot = (Resolve-Path (Join-Path $scriptDir "..\..")).Path
$useExplicitWgpuNativeRoot = -not [string]::IsNullOrWhiteSpace($WgpuNativeRoot)

$packageLeaf = Split-Path -Leaf (Convert-PackagePath $Package)
$packageParent = Split-Path -Leaf (Split-Path -Parent (Convert-PackagePath $Package))
if ([string]::IsNullOrWhiteSpace($AppName)) {
  $AppName = $packageParent
}

$ucrtBin = Join-Path $Msys2Root "ucrt64\bin"
$vulkanDll = Join-Path $ucrtBin "vulkan-1.dll"
$winpthreadDll = Join-Path $ucrtBin "libwinpthread-1.dll"
$packageBuildDir = Join-Path $repoRoot ("_build\native\debug\build\" + (Convert-PackagePath $Package))
$builtExe = Join-Path $packageBuildDir "$packageLeaf.exe"
$appDir = Join-Path $repoRoot (Join-Path $DistDir $AppName)
$appExe = Join-Path $appDir "$AppName.exe"
$manifestPath = Join-Path $appDir "moui-package.json"

Require-Path $ucrtBin "MSYS2 UCRT64 toolchain not found: $ucrtBin"
if ($useExplicitWgpuNativeRoot) {
  $wgpuStaticLib = Join-Path $WgpuNativeRoot "lib\libwgpu_native.a"
  $wgpuTagFile = Join-Path $WgpuNativeRoot "wgpu-native-meta\wgpu-native-git-tag"
  Require-Path $wgpuStaticLib "Missing wgpu static library: $wgpuStaticLib"
  Require-Path $wgpuTagFile "Missing wgpu release metadata: $wgpuTagFile"
}
Require-Path $vulkanDll "Missing Vulkan runtime from MSYS2: $vulkanDll"
Require-Path $winpthreadDll "Missing libwinpthread runtime from MSYS2: $winpthreadDll"

if (-not (Get-Command moon -ErrorAction SilentlyContinue)) {
  throw "MoonBit toolchain is not available in PATH. Install moon and try again."
}

if (-not (Get-Command node -ErrorAction SilentlyContinue)) {
  throw "Node.js is required to validate the package manifest."
}

$env:PATH = "$ucrtBin;$env:PATH"
$env:CC = "x86_64-w64-mingw32-gcc"
$env:CXX = "x86_64-w64-mingw32-g++"
if ($useExplicitWgpuNativeRoot) {
  $env:MBT_WGPU_NATIVE_ROOT = $WgpuNativeRoot
} else {
  Remove-Item Env:MBT_WGPU_NATIVE_ROOT -ErrorAction SilentlyContinue
}

Remove-Item Env:MBT_WGPU_LINK_MODE -ErrorAction SilentlyContinue
Remove-Item Env:MBT_WGPU_NATIVE_LIB -ErrorAction SilentlyContinue
Remove-Item Env:MBT_WGPU_VULKAN_LIB -ErrorAction SilentlyContinue

if (-not (Get-Command $env:CC -ErrorAction SilentlyContinue)) {
  throw "Compiler not found after PATH setup: $env:CC"
}

if (-not (Get-Command $env:CXX -ErrorAction SilentlyContinue)) {
  throw "Compiler not found after PATH setup: $env:CXX"
}

Push-Location $repoRoot
try {
  Write-Host "==> repo root: $repoRoot"
  Write-Host "==> package: $Package"
  Write-Host "==> MSYS2 UCRT64: $ucrtBin"
  if ($useExplicitWgpuNativeRoot) {
    Write-Host "==> WGPU native root: $WgpuNativeRoot"
  } else {
    Write-Host "==> WGPU native root: managed by wgpu_mbt prebuild"
  }

  if (-not $NoBuild) {
    & moon build $Package --target native
    if ($LASTEXITCODE -ne 0) {
      throw "moon build failed with exit code $LASTEXITCODE"
    }
  }

  Require-Path $builtExe "Built executable not found: $builtExe"

  if (Test-Path -LiteralPath $appDir) {
    Remove-Item -LiteralPath $appDir -Recurse -Force
  }
  New-Item -ItemType Directory -Path $appDir | Out-Null

  Copy-Item -LiteralPath $builtExe -Destination $appExe
  Copy-Item -LiteralPath $vulkanDll -Destination (Join-Path $appDir "vulkan-1.dll")
  Copy-Item -LiteralPath $winpthreadDll -Destination (Join-Path $appDir "libwinpthread-1.dll")

  $manifest = @{
    schemaVersion = 1
    platform = "windows"
    outputKind = "portable-folder"
    appName = $AppName
    moonPackage = $Package
    version = $Version
    buildNumber = $BuildNumber
    executable = (Split-Path -Leaf $appExe)
    bundleName = $AppName
    runtimeFiles = @("vulkan-1.dll", "libwinpthread-1.dll")
  } | ConvertTo-Json -Depth 4
  Write-Utf8NoBom $manifestPath $manifest

  & node (Join-Path $repoRoot "scripts\validate-package-manifest.mjs") $manifestPath --platform windows
  if ($LASTEXITCODE -ne 0) {
    throw "manifest validation failed with exit code $LASTEXITCODE"
  }

  Write-Host "==> Wrote $appDir"
}
finally {
  Pop-Location
}