# Shared Coolify API helpers — never prints secret values.
$ErrorActionPreference = "Stop"

function Initialize-CoolifyEnv {
    param(
        [switch]$AllowSecretScript
    )

    if (-not $env:COOLIFY_BASE_URL -and $env:COOLIFY_API_BASE_URL) {
        $env:COOLIFY_BASE_URL = $env:COOLIFY_API_BASE_URL
    }

    if ((-not $env:COOLIFY_API_TOKEN -or -not $env:COOLIFY_BASE_URL) -and $AllowSecretScript) {
        $secretScript = Join-Path $env:USERPROFILE ".renninja-secrets\coolify-api-token.ps1"
        if (Test-Path $secretScript) {
            . $secretScript
            if (-not $env:COOLIFY_BASE_URL -and $env:COOLIFY_API_BASE_URL) {
                $env:COOLIFY_BASE_URL = $env:COOLIFY_API_BASE_URL
            }
        }
    }

    if (-not $env:NEXUS_DOMAIN) {
        $env:NEXUS_DOMAIN = "nexus.ninjakernen.info"
    }

    $missing = @()
    if ([string]::IsNullOrWhiteSpace($env:COOLIFY_API_TOKEN)) { $missing += "COOLIFY_API_TOKEN" }
    if ([string]::IsNullOrWhiteSpace($env:COOLIFY_BASE_URL)) { $missing += "COOLIFY_BASE_URL" }

    if ($missing.Count -gt 0) {
        $hint = @(
            "Load secrets first, for example:"
            "  . `$env:USERPROFILE\.renninja-secrets\coolify-api-token.ps1"
            "Or set COOLIFY_API_TOKEN and COOLIFY_BASE_URL in this session."
        ) -join "`n"
        throw ("Missing required environment variables: " + ($missing -join ", ") + "`n`n" + $hint)
    }

    $script:CoolifyBaseUrl = ($env:COOLIFY_BASE_URL -replace '/$', '')
    $script:CoolifyHeaders = @{
        Authorization = "Bearer $env:COOLIFY_API_TOKEN"
        Accept        = "application/json"
    }

    if ([string]::IsNullOrWhiteSpace($env:COOLIFY_SERVER_ID)) {
        Write-Host "COOLIFY_SERVER_ID not set - resolving from Coolify API..." -ForegroundColor Yellow
        $env:COOLIFY_SERVER_ID = Resolve-CoolifyServerId
        Write-Host "Using server: $($env:COOLIFY_SERVER_ID)" -ForegroundColor DarkGray
    }
}

function Resolve-CoolifyServerId {
    $servers = Invoke-CoolifyApi -Method Get -Path "/api/v1/servers"
    if (-not $servers) {
        throw "No Coolify servers returned. Set COOLIFY_SERVER_ID manually."
    }

    $hostServer = @($servers | Where-Object { $_.is_coolify_host -eq $true })[0]
    if (-not $hostServer) {
        $hostServer = @($servers | Where-Object { $_.name -eq "localhost" })[0]
    }
    if (-not $hostServer) {
        $hostServer = $servers[0]
    }

    if (-not $hostServer.uuid) {
        throw "Could not resolve Coolify server UUID. Set COOLIFY_SERVER_ID manually."
    }

    return [string]$hostServer.uuid
}

function Invoke-CoolifyApi {
    param(
        [Parameter(Mandatory)][string]$Method,
        [Parameter(Mandatory)][string]$Path,
        [object]$Body = $null,
        [int]$TimeoutSec = 120
    )

    $uri = "$script:CoolifyBaseUrl$Path"
    $params = @{
        Method     = $Method
        Uri        = $uri
        Headers    = $script:CoolifyHeaders
        TimeoutSec = $TimeoutSec
    }
    if ($null -ne $Body) {
        $params.ContentType = "application/json"
        $params.Body = ($Body | ConvertTo-Json -Depth 10 -Compress)
    }
    return Invoke-RestMethod @params
}

function Get-CoolifyProjectByName {
    param([Parameter(Mandatory)][string]$Name)
    $projects = Invoke-CoolifyApi -Method Get -Path "/api/v1/projects"
    return @($projects | Where-Object { $_.name -eq $Name })[0]
}

function Get-CoolifyApplicationByName {
    param([Parameter(Mandatory)][string]$Name)
    $apps = Invoke-CoolifyApi -Method Get -Path "/api/v1/applications"
    return @($apps | Where-Object { $_.name -eq $Name })[0]
}

function Get-CoolifyDatabaseByName {
    param([Parameter(Mandatory)][string]$Name)
    $dbs = Invoke-CoolifyApi -Method Get -Path "/api/v1/databases"
    return @($dbs | Where-Object { $_.name -eq $Name })[0]
}

function Set-CoolifyApplicationEnv {
    param(
        [Parameter(Mandatory)][string]$AppUuid,
        [Parameter(Mandatory)][hashtable]$EnvVars
    )

    $existing = Invoke-CoolifyApi -Method Get -Path "/api/v1/applications/$AppUuid/envs"
    $keys = @($existing | ForEach-Object { $_.key })

    foreach ($entry in $EnvVars.GetEnumerator()) {
        $payload = @{
            key        = $entry.Key
            value      = [string]$entry.Value
            is_literal = $true
        }
        if ($keys -contains $entry.Key) {
            Invoke-CoolifyApi -Method Patch -Path "/api/v1/applications/$AppUuid/envs" -Body $payload | Out-Null
        } else {
            Invoke-CoolifyApi -Method Post -Path "/api/v1/applications/$AppUuid/envs" -Body $payload | Out-Null
        }
    }
}

function ConvertTo-Base64Dockerfile {
    param([Parameter(Mandatory)][string]$Path)
    return [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes((Get-Content -LiteralPath $Path -Raw)))
}

function New-RandomBase64Key {
    param([int]$Bytes = 32)
    $buffer = New-Object byte[] $Bytes
    [System.Security.Cryptography.RandomNumberGenerator]::Create().GetBytes($buffer)
    return [Convert]::ToBase64String($buffer)
}

function Get-NexusDomainUrl {
    $domain = $env:NEXUS_DOMAIN.Trim().TrimEnd('/')
    if ($domain -match '^https?://') { return $domain }
    return "https://$domain"
}

function Get-CatboxUploadUrl {
    param([Parameter(Mandatory)][string]$FilePath)

    if (-not (Test-Path -LiteralPath $FilePath)) {
        throw "Upload file not found: $FilePath"
    }

    $uploadPath = $FilePath
    $tempCopy = $null
    $ext = [IO.Path]::GetExtension($FilePath).ToLowerInvariant()
    if ($ext -in @('.exe', '.dll', '.bat', '.cmd', '.ps1', '.msi')) {
        $tempCopy = Join-Path $env:TEMP ("nexus-catbox-" + [Guid]::NewGuid().ToString("N") + ".bin")
        Copy-Item -LiteralPath $FilePath -Destination $tempCopy -Force
        $uploadPath = $tempCopy
    }

    $out = Join-Path $env:TEMP ("nexus-catbox-" + [Guid]::NewGuid().ToString("N") + ".txt")
    try {
        curl.exe -sS -F "reqtype=fileupload" -F "fileToUpload=@$uploadPath" "https://catbox.moe/user/api.php" -o $out
        if ($LASTEXITCODE -ne 0) {
            throw "curl exit code $LASTEXITCODE"
        }
        $url = (Get-Content $out -Raw).Trim()
        if ($url -notmatch '^https?://') {
            throw $url
        }
        return $url
    } finally {
        Remove-Item $out -Force -ErrorAction SilentlyContinue
        if ($tempCopy) { Remove-Item $tempCopy -Force -ErrorAction SilentlyContinue }
    }
}
