param(
    [string]$InstallDir = "",
    [switch]$NoPath,
    [switch]$Uninstall,
    [switch]$Quiet
)

$ErrorActionPreference = "Stop"
$utf8NoBom = New-Object System.Text.UTF8Encoding($false)

function Write-Step {
    param([string]$Message)
    if (-not $Quiet) { Write-Host $Message }
}

function Normalize-PathText {
    param([string]$Path)
    if ([string]::IsNullOrWhiteSpace($Path)) { return "" }
    return ([System.IO.Path]::GetFullPath($Path)).TrimEnd('\', '/')
}

function Get-DefaultInstallDir {
    if (-not [string]::IsNullOrWhiteSpace($env:LOCALAPPDATA)) {
        return (Join-Path $env:LOCALAPPDATA "Programs\Sura")
    }
    return (Join-Path $HOME ".sura")
}

function Get-DirectoryByteSize {
    param([string]$Path)
    if (-not (Test-Path -LiteralPath $Path)) { return 0L }
    $total = 0L
    foreach ($file in Get-ChildItem -LiteralPath $Path -Recurse -File -ErrorAction SilentlyContinue) {
        $total += [int64]$file.Length
    }
    return $total
}

function Format-ByteSize {
    param([int64]$Bytes)
    if ($Bytes -ge 1GB) { return ("{0:N1} GB" -f ($Bytes / 1GB)) }
    if ($Bytes -ge 1MB) { return ("{0:N1} MB" -f ($Bytes / 1MB)) }
    if ($Bytes -ge 1KB) { return ("{0:N1} KB" -f ($Bytes / 1KB)) }
    return ("{0} bytes" -f $Bytes)
}

function Get-UserPathParts {
    $raw = [Environment]::GetEnvironmentVariable("Path", "User")
    if ([string]::IsNullOrWhiteSpace($raw)) { return @() }
    return @($raw -split ";" | Where-Object { -not [string]::IsNullOrWhiteSpace($_) })
}

function Set-UserPathParts {
    param([string[]]$Parts)
    [Environment]::SetEnvironmentVariable("Path", ($Parts -join ";"), "User")
}

function Add-UserPathEntry {
    param([string]$Entry)
    $want = Normalize-PathText $Entry
    $parts = @(Get-UserPathParts | Where-Object {
        -not [string]::Equals((Normalize-PathText $_), $want, [System.StringComparison]::OrdinalIgnoreCase)
    })
    $parts = @($Entry) + $parts
    Set-UserPathParts $parts
}

function Remove-UserPathEntry {
    param([string]$Entry)
    $want = Normalize-PathText $Entry
    $parts = @(Get-UserPathParts | Where-Object {
        -not [string]::Equals((Normalize-PathText $_), $want, [System.StringComparison]::OrdinalIgnoreCase)
    })
    Set-UserPathParts $parts
}

function Write-CmdLauncher {
    param([string]$Path, [string]$Target)
    $content = "@echo off`r`n`"%~dp0$Target`" %*`r`n"
    [System.IO.File]::WriteAllText($Path, $content, [System.Text.Encoding]::ASCII)
}

function Resolve-PayloadDir {
    $sourceRoot = if (-not [string]::IsNullOrWhiteSpace($PSScriptRoot)) {
        $PSScriptRoot
    } else {
        Split-Path -Parent $PSCommandPath
    }
    foreach ($candidate in @(
        (Join-Path $sourceRoot "payload"),
        (Join-Path (Split-Path -Parent $sourceRoot) "payload")
    )) {
        if (Test-Path -LiteralPath $candidate) {
            return $candidate
        }
    }
    return (Join-Path $sourceRoot "payload")
}

if ([string]::IsNullOrWhiteSpace($InstallDir)) {
    $InstallDir = Get-DefaultInstallDir
}
$payloadBytes = Get-DirectoryByteSize (Join-Path $PSScriptRoot "payload")
$estimatedInstallBytes = $payloadBytes + 1MB
$InstallDir = [System.IO.Path]::GetFullPath($InstallDir)
$binDir = Join-Path $InstallDir "bin"

if ($Uninstall) {
    if (-not $NoPath) {
        Remove-UserPathEntry $binDir
    }
    if (Test-Path -LiteralPath $InstallDir) {
        Remove-Item -LiteralPath $InstallDir -Recurse -Force
    }
    Write-Step "Sura Language uninstalled from $InstallDir"
    return
}

$payload = Resolve-PayloadDir
$engineSource = Join-Path $payload "SuraLanguage.exe"
$legacyEngineSource = Join-Path $payload "SuraFinal.exe"
$pkgSource = Join-Path $payload "surapkg.exe"
if (-not (Test-Path -LiteralPath $engineSource)) {
    $engineSource = $legacyEngineSource
}
if (-not (Test-Path -LiteralPath $engineSource)) {
    throw "installer payload is missing the Sura Language engine"
}

New-Item -ItemType Directory -Force -Path $binDir | Out-Null
$legacyInstalledEngine = Join-Path $binDir "SuraEngine.exe"
if (Test-Path -LiteralPath $legacyInstalledEngine -PathType Leaf) {
    Remove-Item -LiteralPath $legacyInstalledEngine -Force
}
Copy-Item -LiteralPath $engineSource -Destination (Join-Path $binDir "SuraLanguage.exe") -Force
Copy-Item -LiteralPath $(if (Test-Path -LiteralPath $legacyEngineSource) { $legacyEngineSource } else { $engineSource }) -Destination (Join-Path $binDir "SuraFinal.exe") -Force
if (Test-Path -LiteralPath $pkgSource) {
    Copy-Item -LiteralPath $pkgSource -Destination (Join-Path $binDir "surapkg.exe") -Force
}

Write-CmdLauncher (Join-Path $binDir "sura.cmd") "SuraLanguage.exe"
if (Test-Path -LiteralPath (Join-Path $binDir "surapkg.exe")) {
    Write-CmdLauncher (Join-Path $binDir "surapkg.cmd") "surapkg.exe"
}

$installInfo = [ordered]@{
    schema = "sura.installation.v1"
    product_name = "Sura Language"
    version = "1.10.0"
    installed_utc = [DateTime]::UtcNow.ToString("o")
    install_dir = $InstallDir
    bin_dir = $binDir
    commands = @("sura", "surapkg")
    engine = "SuraLanguage.exe"
    path_added = (-not $NoPath)
}
[System.IO.File]::WriteAllText(
    (Join-Path $InstallDir "installation.json"),
    ($installInfo | ConvertTo-Json -Depth 4),
    $utf8NoBom
)

if (-not $NoPath) {
    Add-UserPathEntry $binDir
    Write-Step "Added $binDir to the front of the user PATH. Open a new terminal before running sura."
}

Write-Step "Sura Language installed to $InstallDir"
Write-Step "Run: sura --help"