param(
    [string]$BaseUrl = 'https://argus.kusoft.xyz',
    [Parameter(Mandatory = $true)]
    [string]$Username,
    [Parameter(Mandatory = $true)]
    [string]$Password,
    [Parameter(Mandatory = $true)]
    [string]$Slug,
    [Parameter(Mandatory = $true)]
    [string]$Name,
    [Parameter(Mandatory = $true)]
    [string]$Summary,
    [Parameter(Mandatory = $true)]
    [string]$Description,
    [Parameter(Mandatory = $true)]
    [string]$AndroidPackageName,
    [Parameter(Mandatory = $true)]
    [string]$Version,
    [Parameter(Mandatory = $true)]
    [ValidateRange(1, [int]::MaxValue)]
    [int]$AndroidVersionCode,
    [Parameter(Mandatory = $true)]
    [string]$PackagePath,
    [string]$Channel = 'stable',
    [string]$Platform = 'android',
    [string]$PackageKind = 'apk',
    [string]$Notes,
    [string]$RepositoryUrl,
    [string]$HomepageUrl = 'https://ikar.kusoft.xyz',
    [switch]$Unlisted
)

$ErrorActionPreference = 'Stop'
Add-Type -AssemblyName System.Net.Http

function Read-HttpBody([System.Net.Http.HttpResponseMessage]$Response) {
    if ($null -eq $Response.Content) {
        return ''
    }

    return $Response.Content.ReadAsStringAsync().GetAwaiter().GetResult()
}

function Ensure-Success(
    [System.Net.Http.HttpResponseMessage]$Response,
    [string]$Operation
) {
    if ($Response.IsSuccessStatusCode) {
        return
    }

    $body = Read-HttpBody $Response
    throw "$Operation failed with status $([int]$Response.StatusCode) ($($Response.ReasonPhrase)). Body: $body"
}

function New-JsonContent([string]$Json) {
    return [System.Net.Http.StringContent]::new($Json, [System.Text.Encoding]::UTF8, 'application/json')
}

$resolvedPackagePath = (Resolve-Path -LiteralPath $PackagePath).Path
if (-not (Test-Path $resolvedPackagePath)) {
    throw "Package file was not found: $resolvedPackagePath"
}

$baseUri = $BaseUrl.TrimEnd('/')
$cookieContainer = [System.Net.CookieContainer]::new()
$handler = [System.Net.Http.HttpClientHandler]::new()
$handler.CookieContainer = $cookieContainer
$handler.UseCookies = $true
$client = [System.Net.Http.HttpClient]::new($handler)
$client.Timeout = [TimeSpan]::FromMinutes(15)

try {
    $loginPayload = @{
        username = $Username
        password = $Password
    } | ConvertTo-Json -Compress

    $loginResponse = $client.PostAsync(
        "$baseUri/api/admin/session/login",
        (New-JsonContent $loginPayload)
    ).GetAwaiter().GetResult()
    Ensure-Success $loginResponse 'Argus login'

    $appPayload = @{
        name = $Name
        summary = $Summary
        description = $Description
        androidPackageName = $AndroidPackageName
        repositoryUrl = if ([string]::IsNullOrWhiteSpace($RepositoryUrl)) { $null } else { $RepositoryUrl }
        homepageUrl = if ([string]::IsNullOrWhiteSpace($HomepageUrl)) { $null } else { $HomepageUrl }
        isListed = (-not $Unlisted)
    } | ConvertTo-Json -Compress

    $appResponse = $client.PutAsync(
        "$baseUri/api/admin/apps/$Slug",
        (New-JsonContent $appPayload)
    ).GetAwaiter().GetResult()
    Ensure-Success $appResponse 'Argus app metadata update'

    $form = [System.Net.Http.MultipartFormDataContent]::new()
    $fields = [ordered]@{
        Version = $Version
        Channel = $Channel
        Platform = $Platform
        PackageKind = $PackageKind
        AndroidVersionCode = [string]$AndroidVersionCode
    }

    foreach ($entry in $fields.GetEnumerator()) {
        $form.Add([System.Net.Http.StringContent]::new($entry.Value, [System.Text.Encoding]::UTF8), $entry.Key)
    }

    if (-not [string]::IsNullOrWhiteSpace($Notes)) {
        $form.Add([System.Net.Http.StringContent]::new($Notes, [System.Text.Encoding]::UTF8), 'Notes')
    }

    $fileStream = [System.IO.File]::OpenRead($resolvedPackagePath)
    try {
        $fileContent = [System.Net.Http.StreamContent]::new($fileStream)
        $fileContent.Headers.ContentType = [System.Net.Http.Headers.MediaTypeHeaderValue]::Parse('application/vnd.android.package-archive')
        $form.Add($fileContent, 'Package', [System.IO.Path]::GetFileName($resolvedPackagePath))

        $releaseResponse = $client.PostAsync(
            "$baseUri/api/admin/apps/$Slug/releases",
            $form
        ).GetAwaiter().GetResult()
        Ensure-Success $releaseResponse 'Argus release upload'

        $releaseBody = Read-HttpBody $releaseResponse
        if (-not [string]::IsNullOrWhiteSpace($releaseBody)) {
            Write-Output $releaseBody
        }
    } finally {
        $fileStream.Dispose()
        $form.Dispose()
    }
} finally {
    $client.Dispose()
    $handler.Dispose()
}
