<#
.SYNOPSIS
    Build a portable Windows distribution of LedGrab.

.DESCRIPTION
    Downloads embedded Python, installs all dependencies, copies app code,
    builds the frontend bundle, and produces a self-contained ZIP.

.PARAMETER Version
    Version string (e.g. "0.1.0" or "v0.1.0"). Auto-detected from git tag
    or __init__.py if omitted.

.PARAMETER PythonVersion
    Embedded Python version to download. Default: 3.11.9

.PARAMETER SkipFrontend
    Skip npm ci + npm run build (use if frontend is already built).

.PARAMETER SkipPerf
    Skip installing optional [perf] extras (dxcam, bettercam, windows-capture).

.EXAMPLE
    .\build-dist.ps1
    .\build-dist.ps1 -Version "0.2.0"
    .\build-dist.ps1 -SkipFrontend -SkipPerf
#>
param(
    [string]$Version = "",
    [string]$PythonVersion = "3.11.9",
    [switch]$SkipFrontend,
    [switch]$SkipPerf
)

$ErrorActionPreference = 'Stop'
$ProgressPreference = 'SilentlyContinue'  # faster downloads

$ScriptRoot = $PSScriptRoot
$BuildDir = Join-Path $ScriptRoot "build"
$DistName = "LedGrab"
$DistDir = Join-Path $BuildDir $DistName
$ServerDir = Join-Path $ScriptRoot "server"
$PythonDir = Join-Path $DistDir "python"
$AppDir = Join-Path $DistDir "app"

# ── Version detection ──────────────────────────────────────────

if (-not $Version) {
    # Try git tag
    try {
        $gitTag = git describe --tags --exact-match 2>$null
        if ($gitTag) { $Version = $gitTag }
    } catch {}
}
if (-not $Version) {
    # Try env var (CI)
    if ($env:GITEA_REF_NAME) { $Version = $env:GITEA_REF_NAME }
    elseif ($env:GITHUB_REF_NAME) { $Version = $env:GITHUB_REF_NAME }
}
if (-not $Version) {
    # Parse from __init__.py
    $initFile = Join-Path $ServerDir "src\wled_controller\__init__.py"
    $match = Select-String -Path $initFile -Pattern '__version__\s*=\s*"([^"]+)"'
    if ($match) { $Version = $match.Matches[0].Groups[1].Value }
}
if (-not $Version) { $Version = "0.0.0" }

# Strip leading 'v' for filenames
$VersionClean = $Version -replace '^v', ''
$ZipName = "LedGrab-v${VersionClean}-win-x64.zip"

Write-Host "=== Building LedGrab v${VersionClean} ===" -ForegroundColor Cyan
Write-Host "  Python: $PythonVersion"
Write-Host "  Output: build\$ZipName"
Write-Host ""

# ── Clean ──────────────────────────────────────────────────────

if (Test-Path $DistDir) {
    Write-Host "[1/8] Cleaning previous build..."
    Remove-Item -Recurse -Force $DistDir
}
New-Item -ItemType Directory -Path $DistDir -Force | Out-Null

# ── Download embedded Python ───────────────────────────────────

$PythonZipUrl = "https://www.python.org/ftp/python/${PythonVersion}/python-${PythonVersion}-embed-amd64.zip"
$PythonZipPath = Join-Path $BuildDir "python-embed.zip"

Write-Host "[2/8] Downloading embedded Python ${PythonVersion}..."
if (-not (Test-Path $PythonZipPath)) {
    Invoke-WebRequest -Uri $PythonZipUrl -OutFile $PythonZipPath
}
Write-Host "  Extracting to python/..."
Expand-Archive -Path $PythonZipPath -DestinationPath $PythonDir -Force

# ── Patch ._pth to enable site-packages ────────────────────────

Write-Host "[3/8] Patching Python path configuration..."
$pthFile = Get-ChildItem -Path $PythonDir -Filter "python*._pth" | Select-Object -First 1
if (-not $pthFile) { throw "Could not find python*._pth in $PythonDir" }

$pthContent = Get-Content $pthFile.FullName -Raw
# Uncomment 'import site'
$pthContent = $pthContent -replace '#\s*import site', 'import site'
# Add Lib\site-packages if not present
if ($pthContent -notmatch 'Lib\\site-packages') {
    $pthContent = $pthContent.TrimEnd() + "`nLib\site-packages`n"
}
# Embedded Python ._pth overrides PYTHONPATH, so add the app source path
# directly for wled_controller to be importable
if ($pthContent -notmatch '\.\.[/\\]app[/\\]src') {
    $pthContent = $pthContent.TrimEnd() + "`n..\app\src`n"
}
Set-Content -Path $pthFile.FullName -Value $pthContent -NoNewline
Write-Host "  Patched $($pthFile.Name)"

# ── Install pip ────────────────────────────────────────────────

Write-Host "[4/8] Installing pip..."
$GetPipPath = Join-Path $BuildDir "get-pip.py"
if (-not (Test-Path $GetPipPath)) {
    Invoke-WebRequest -Uri "https://bootstrap.pypa.io/get-pip.py" -OutFile $GetPipPath
}
$python = Join-Path $PythonDir "python.exe"
$ErrorActionPreference = 'Continue'
& $python $GetPipPath --no-warn-script-location 2>&1 | Out-Null
$ErrorActionPreference = 'Stop'
if ($LASTEXITCODE -ne 0) { throw "Failed to install pip" }

# ── Install dependencies ──────────────────────────────────────

Write-Host "[5/8] Installing dependencies..."
$extras = "camera,notifications,tray"
if (-not $SkipPerf) { $extras += ",perf" }

# Install the project (pulls all deps via pyproject.toml), then remove
# the installed package itself — PYTHONPATH handles app code loading.
$ErrorActionPreference = 'Continue'
& $python -m pip install --no-warn-script-location "${ServerDir}[${extras}]" 2>&1 | ForEach-Object {
    if ($_ -match 'ERROR|Failed') { Write-Host "  $_" -ForegroundColor Red }
}
$ErrorActionPreference = 'Stop'
if ($LASTEXITCODE -ne 0) {
    Write-Host "  Some optional deps may have failed (continuing)..." -ForegroundColor Yellow
}

# Remove the installed wled_controller package to avoid duplication
$sitePackages = Join-Path $PythonDir "Lib\site-packages"
Get-ChildItem -Path $sitePackages -Filter "wled*" -Directory | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
Get-ChildItem -Path $sitePackages -Filter "wled*.dist-info" -Directory | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue

# Clean up caches and test files to reduce size
Write-Host "  Cleaning up caches..."
Get-ChildItem -Path $sitePackages -Recurse -Directory -Filter "__pycache__" | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
Get-ChildItem -Path $sitePackages -Recurse -Directory -Filter "tests" | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
Get-ChildItem -Path $sitePackages -Recurse -Directory -Filter "test" | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue

# ── Build frontend ─────────────────────────────────────────────

if (-not $SkipFrontend) {
    Write-Host "[6/8] Building frontend bundle..."
    Push-Location $ServerDir
    try {
        $ErrorActionPreference = 'Continue'
        & npm ci --loglevel error 2>&1 | Out-Null
        & npm run build 2>&1 | ForEach-Object {
            $line = "$_"
            if ($line -and $line -notmatch 'RemoteException') { Write-Host "  $line" }
        }
        $ErrorActionPreference = 'Stop'
    } finally {
        Pop-Location
    }
} else {
    Write-Host "[6/8] Skipping frontend build (--SkipFrontend)"
}

# ── Copy application files ─────────────────────────────────────

Write-Host "[7/8] Copying application files..."
New-Item -ItemType Directory -Path $AppDir -Force | Out-Null

# Copy source code (includes static/dist bundle, templates, locales)
$srcDest = Join-Path $AppDir "src"
Copy-Item -Path (Join-Path $ServerDir "src") -Destination $srcDest -Recurse

# Copy config
$configDest = Join-Path $AppDir "config"
Copy-Item -Path (Join-Path $ServerDir "config") -Destination $configDest -Recurse

# Create empty data/ and logs/ directories
New-Item -ItemType Directory -Path (Join-Path $DistDir "data") -Force | Out-Null
New-Item -ItemType Directory -Path (Join-Path $DistDir "logs") -Force | Out-Null

# Clean up source maps and __pycache__ from app code
Get-ChildItem -Path $srcDest -Recurse -Filter "*.map" | Remove-Item -Force -ErrorAction SilentlyContinue
Get-ChildItem -Path $srcDest -Recurse -Directory -Filter "__pycache__" | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue

# ── Create launcher ────────────────────────────────────────────

Write-Host "[8/8] Creating launcher..."

$launcherContent = @'
@echo off
cd /d "%~dp0"

:: Set paths
set PYTHONPATH=%~dp0app\src
set WLED_CONFIG_PATH=%~dp0app\config\default_config.yaml

:: Create data directory if missing
if not exist "%~dp0data" mkdir "%~dp0data"
if not exist "%~dp0logs" mkdir "%~dp0logs"

:: Start the server (tray icon handles UI and exit)
"%~dp0python\pythonw.exe" -m wled_controller
'@

$launcherContent = $launcherContent -replace '%VERSION%', $VersionClean
$launcherPath = Join-Path $DistDir "LedGrab.bat"
Set-Content -Path $launcherPath -Value $launcherContent -Encoding ASCII

# Copy hidden launcher VBS
$scriptsDir = Join-Path $DistDir "scripts"
New-Item -ItemType Directory -Path $scriptsDir -Force | Out-Null
Copy-Item -Path (Join-Path $ServerDir "scripts\start-hidden.vbs") -Destination $scriptsDir

# ── Create ZIP ─────────────────────────────────────────────────

$ZipPath = Join-Path $BuildDir $ZipName
if (Test-Path $ZipPath) { Remove-Item -Force $ZipPath }

Write-Host ""
Write-Host "Creating $ZipName..." -ForegroundColor Cyan

# Use 7-Zip if available (faster, handles locked files), else fall back to Compress-Archive
$7z = Get-Command 7z -ErrorAction SilentlyContinue
if ($7z) {
    & 7z a -tzip -mx=7 $ZipPath "$DistDir\*" | Select-Object -Last 3
} else {
    Compress-Archive -Path "$DistDir\*" -DestinationPath $ZipPath -CompressionLevel Optimal
}

$zipSize = (Get-Item $ZipPath).Length / 1MB
Write-Host ""
Write-Host "=== Build complete ===" -ForegroundColor Green
Write-Host "  Archive: $ZipPath"
Write-Host "  Size: $([math]::Round($zipSize, 1)) MB"
Write-Host ""
