param(
    [ValidateSet("start", "status", "stop", "worker")]
    [string]$Action = "status",

    [string]$Url = "https://huggingface.co/lmstudio-community/Qwen3-Coder-30B-A3B-Instruct-GGUF/resolve/main/Qwen3-Coder-30B-A3B-Instruct-Q6_K.gguf",
    [string]$OutputPath = "models\gguf\1c\qwen3-coder-30b-a3b-instruct-q6_k\Qwen3-Coder-30B-A3B-Instruct-Q6_K.gguf",
    [Int64]$ExpectedBytes = 25104724288,
    [string]$PidFile = "reports\qwen3-coder-q6-download.pid",
    [string]$StatusFile = "reports\qwen3-coder-q6-download-status.json",
    [string]$LogFile = "reports\qwen3-coder-q6-download.log"
)

$ErrorActionPreference = "Stop"

function Get-DownloadBytes {
    if (Test-Path -LiteralPath $OutputPath) {
        return (Get-Item -LiteralPath $OutputPath).Length
    }
    return 0
}

function Write-DownloadStatus {
    param(
        [string]$State,
        [int]$ExitCode = 0,
        [string]$Message = ""
    )

    $bytes = Get-DownloadBytes
    $percent = if ($ExpectedBytes -gt 0) { [math]::Round(($bytes / $ExpectedBytes) * 100, 4) } else { 0 }
    $payload = [ordered]@{
        state = $State
        bytes = $bytes
        expected_bytes = $ExpectedBytes
        percent = $percent
        output_path = (Resolve-Path -LiteralPath (Split-Path -Parent $OutputPath) -ErrorAction SilentlyContinue).Path
        file = $OutputPath
        log = $LogFile
        exit_code = $ExitCode
        message = $Message
        updated_at = (Get-Date).ToString("o")
    }
    $StatusFileParent = Split-Path -Parent $StatusFile
    if ($StatusFileParent) {
        New-Item -ItemType Directory -Force -Path $StatusFileParent | Out-Null
    }
    $payload | ConvertTo-Json -Depth 4 | Set-Content -LiteralPath $StatusFile -Encoding UTF8
}

function Get-WorkerProcess {
    if (-not (Test-Path -LiteralPath $PidFile)) {
        return $null
    }
    $rawPid = (Get-Content -LiteralPath $PidFile -ErrorAction SilentlyContinue | Select-Object -First 1)
    if (-not $rawPid) {
        return $null
    }
    try {
        return Get-Process -Id ([int]$rawPid) -ErrorAction Stop
    } catch {
        return $null
    }
}

function Show-Status {
    $process = Get-WorkerProcess
    if ($process) {
        Write-DownloadStatus -State "running" -Message "worker pid $($process.Id)"
    } elseif (Test-Path -LiteralPath $StatusFile) {
        $status = Get-Content -LiteralPath $StatusFile -Raw
        Write-Output $status
        return
    } else {
        Write-DownloadStatus -State "not_started"
    }
    Get-Content -LiteralPath $StatusFile -Raw
}

function Start-Worker {
    $existing = Get-WorkerProcess
    if ($existing) {
        Write-Output "Download already running, pid $($existing.Id)."
        Show-Status
        return
    }

    New-Item -ItemType Directory -Force -Path (Split-Path -Parent $OutputPath) | Out-Null
    New-Item -ItemType Directory -Force -Path (Split-Path -Parent $LogFile) | Out-Null
    Write-DownloadStatus -State "starting"

    $arguments = @(
        "-NoProfile",
        "-ExecutionPolicy", "Bypass",
        "-File", $PSCommandPath,
        "-Action", "worker",
        "-Url", $Url,
        "-OutputPath", $OutputPath,
        "-ExpectedBytes", "$ExpectedBytes",
        "-PidFile", $PidFile,
        "-StatusFile", $StatusFile,
        "-LogFile", $LogFile
    )
    $process = Start-Process -FilePath "pwsh" -ArgumentList $arguments -WorkingDirectory (Get-Location) -WindowStyle Hidden -PassThru
    Set-Content -LiteralPath $PidFile -Value $process.Id -Encoding ASCII
    Write-Output "Started Q6 download worker, pid $($process.Id)."
    Start-Sleep -Seconds 1
    Show-Status
}

function Stop-Worker {
    $process = Get-WorkerProcess
    if ($process) {
        Stop-Process -Id $process.Id -Force
        Write-DownloadStatus -State "stopped" -Message "stopped pid $($process.Id)"
    } else {
        Write-DownloadStatus -State "stopped" -Message "no worker process"
    }
    if (Test-Path -LiteralPath $PidFile) {
        Remove-Item -LiteralPath $PidFile -Force
    }
    Show-Status
}

function Invoke-Worker {
    New-Item -ItemType Directory -Force -Path (Split-Path -Parent $OutputPath) | Out-Null
    New-Item -ItemType Directory -Force -Path (Split-Path -Parent $LogFile) | Out-Null
    Write-DownloadStatus -State "running" -Message "worker started"

    while ((Get-DownloadBytes) -lt $ExpectedBytes) {
        $before = Get-DownloadBytes
        Add-Content -LiteralPath $LogFile -Encoding UTF8 -Value "[$((Get-Date).ToString('o'))] curl resume from $before"
        & curl.exe -L --fail --retry 8 --retry-delay 5 --retry-all-errors --connect-timeout 60 --speed-time 120 --speed-limit 10240 -C - -o $OutputPath $Url 2>&1 |
            Tee-Object -FilePath $LogFile -Append | Out-Null
        $exitCode = $LASTEXITCODE
        $after = Get-DownloadBytes
        if ($after -ge $ExpectedBytes) {
            Write-DownloadStatus -State "complete" -ExitCode $exitCode -Message "download complete"
            if (Test-Path -LiteralPath $PidFile) {
                Remove-Item -LiteralPath $PidFile -Force
            }
            return
        }
        Write-DownloadStatus -State "retrying" -ExitCode $exitCode -Message "downloaded $after of $ExpectedBytes bytes"
        Start-Sleep -Seconds 10
    }

    Write-DownloadStatus -State "complete" -Message "download complete"
    if (Test-Path -LiteralPath $PidFile) {
        Remove-Item -LiteralPath $PidFile -Force
    }
}

switch ($Action) {
    "start" { Start-Worker }
    "status" { Show-Status }
    "stop" { Stop-Worker }
    "worker" { Invoke-Worker }
}
