$ErrorActionPreference = "Stop"

$QuerymtRepo = "querymt/querymt"
$QmtuiRepo = "querymt/qmtui"
$Channel = if ($env:QMT_CHANNEL -eq "nightly") { "nightly" } else { "latest" }
$InstallDir = if ($env:QMT_INSTALL_DIR) { $env:QMT_INSTALL_DIR } else { Join-Path $env:USERPROFILE ".local\bin" }

$arch = $env:PROCESSOR_ARCHITECTURE
switch ($arch) {
    "AMD64" { $Target = "x86_64-pc-windows-msvc" }
    "ARM64" { $Target = "aarch64-pc-windows-msvc" }
    default { throw "Unsupported Windows architecture: $arch" }
}

function Get-RepoForBinary([string]$Binary) {
    switch ($Binary) {
        "qmt" { return $QuerymtRepo }
        "qmtcode" { return $QuerymtRepo }
        "qmtui" { return $QmtuiRepo }
        default { throw "Unsupported binary: $Binary" }
    }
}

function Get-ReleaseApiUrl([string]$Repo) {
    if ($Channel -eq "nightly") {
        return "https://api.github.com/repos/$Repo/releases/tags/nightly"
    }
    return "https://api.github.com/repos/$Repo/releases/latest"
}

# Cache release metadata per repo to avoid redundant API calls (rate-limit friendly).
$script:ReleaseCache = @{}

function Get-Release([string]$Repo) {
    if (-not $script:ReleaseCache.ContainsKey($Repo)) {
        $apiUrl = Get-ReleaseApiUrl -Repo $Repo
        Write-Host "Fetching release metadata from $Repo ($Channel)..."
        try {
            $script:ReleaseCache[$Repo] = Invoke-RestMethod -Uri $apiUrl
        } catch {
            throw "Failed to fetch release from $apiUrl -- $($_.Exception.Message)"
        }
    }
    return $script:ReleaseCache[$Repo]
}

function Get-AssetUrl([string]$Binary) {
    $repo = Get-RepoForBinary -Binary $Binary
    $release = Get-Release -Repo $repo
    if ($Channel -eq "nightly") {
        $regex = "^$Binary-nightly-.*-$Target\.zip$"
    } else {
        $regex = "^$Binary-.*-$Target\.zip$"
    }

    $asset = $release.assets | Where-Object { $_.name -match $regex } | Select-Object -First 1
    if (-not $asset) {
        throw "Could not find asset for $Binary in $repo ($Target, $Channel)"
    }

    return $asset.browser_download_url
}

function Install-Binary([string]$Binary) {
    $tmpRoot = Join-Path $env:TEMP ("qmt-install-" + [Guid]::NewGuid().ToString("N"))
    New-Item -ItemType Directory -Path $tmpRoot | Out-Null

    try {
        $zipPath = Join-Path $tmpRoot "$Binary.zip"
        $extractDir = Join-Path $tmpRoot "extract"
        $repo = Get-RepoForBinary -Binary $Binary

        $url = Get-AssetUrl -Binary $Binary
        Write-Host "Downloading $Binary from $repo ($Channel, $Target)..."
        Invoke-WebRequest -Uri $url -OutFile $zipPath

        Expand-Archive -Path $zipPath -DestinationPath $extractDir -Force

        $exe = Get-ChildItem -Path $extractDir -Recurse -Filter "$Binary.exe" | Select-Object -First 1
        if (-not $exe) {
            throw "Failed to locate $Binary.exe in extracted archive"
        }

        New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null
        Copy-Item $exe.FullName -Destination (Join-Path $InstallDir "$Binary.exe") -Force
    }
    finally {
        Remove-Item -Path $tmpRoot -Recurse -Force -ErrorAction SilentlyContinue
    }
}

function Show-Version([string]$Binary) {
    & (Join-Path $InstallDir "$Binary.exe") --version
}

Install-Binary -Binary "qmt"
Install-Binary -Binary "qmtcode"
Install-Binary -Binary "qmtui"

Write-Host "Installed to: $InstallDir"

$pathParts = [Environment]::GetEnvironmentVariable("Path", "User") -split ";"
if ($pathParts -notcontains $InstallDir) {
    $newPath = if ([string]::IsNullOrEmpty([Environment]::GetEnvironmentVariable("Path", "User"))) {
        $InstallDir
    } else {
        [Environment]::GetEnvironmentVariable("Path", "User") + ";" + $InstallDir
    }
    [Environment]::SetEnvironmentVariable("Path", $newPath, "User")
    Write-Host "Added $InstallDir to user PATH. Restart your shell to pick it up."
}

Show-Version -Binary "qmt"
Show-Version -Binary "qmtcode"
Show-Version -Binary "qmtui"
