param(
    [string]$Slug = 'qsfera-mobile',
    [string]$Name,
    [string]$Summary = 'Android client for QSfera server.',
    [string]$Description = 'Android client for QSfera server, prepared for Argus publication.',
    [string]$Version,
    [string]$Channel = 'stable',
    [string]$Platform = 'android',
    [string]$Notes,
    [string]$RepositoryUrl = 'https://git.kusoft.xyz/sevenhill/QSfera.git',
    [string]$HomepageUrl = 'https://qsfera.kusoft.xyz',
    [switch]$Unlisted,
    [switch]$SkipSigningInitialization
)

$ErrorActionPreference = 'Stop'

function Require-Tool([string]$Path, [string]$Label) {
    if (-not (Test-Path $Path)) {
        throw "$Label was not found: $Path"
    }
}

function Get-ApkBadgingValue([string]$BadgingText, [string]$Pattern) {
    $match = [regex]::Match($BadgingText, $Pattern, [System.Text.RegularExpressions.RegexOptions]::Multiline)
    if (-not $match.Success) {
        return $null
    }
    return $match.Groups[1].Value
}

function Read-Properties([string]$Path) {
    $result = @{}
    foreach ($line in Get-Content $Path) {
        $trimmed = $line.Trim()
        if ($trimmed.Length -eq 0 -or $trimmed.StartsWith('#')) {
            continue
        }

        $separator = $trimmed.IndexOf('=')
        if ($separator -le 0) {
            continue
        }

        $key = $trimmed.Substring(0, $separator).Trim()
        $value = $trimmed.Substring($separator + 1).Trim()
        $result[$key] = $value
    }
    return $result
}

function Resolve-JavaHome {
    $candidates = @(
        $env:JAVA_HOME,
        'C:\Program Files\Android\Android Studio\jbr',
        'C:\Program Files\Android\openjdk\jdk-21.0.8'
    ) | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }

    foreach ($candidate in $candidates) {
        $java = Join-Path $candidate 'bin\java.exe'
        if (Test-Path $java) {
            return $candidate
        }
    }

    throw 'java.exe was not found. Set JAVA_HOME to a JDK path.'
}

function Resolve-AndroidHome {
    $candidates = @(
        $env:ANDROID_HOME,
        "$env:LOCALAPPDATA\Android\Sdk"
    ) | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }

    foreach ($candidate in $candidates) {
        if (Test-Path (Join-Path $candidate 'build-tools')) {
            return $candidate
        }
    }

    throw 'Android SDK was not found. Set ANDROID_HOME to the SDK path.'
}

function Resolve-ArgusPlatform([string[]]$NativeCodes) {
    $normalized = $NativeCodes | Where-Object { $_ } | ForEach-Object { $_.Trim().ToLowerInvariant() }
    $allUniversalAbis = @('arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64')
    if (@($allUniversalAbis | Where-Object { $normalized -contains $_ }).Count -eq $allUniversalAbis.Count) {
        return 'android-universal'
    }
    if ($normalized -contains 'arm64-v8a') {
        return 'android-arm64'
    }
    if ($normalized -contains 'armeabi-v7a') {
        return 'android-armv7'
    }
    if ($normalized -contains 'x86_64') {
        return 'android-x86_64'
    }
    if ($normalized -contains 'x86') {
        return 'android-x86'
    }
    return 'android'
}

function Find-FirstTool([string]$AndroidHome, [string]$ToolName) {
    $tool = Get-ChildItem -Path (Join-Path $AndroidHome 'build-tools') -Recurse -File -Filter $ToolName |
        Sort-Object FullName -Descending |
        Select-Object -First 1
    if (-not $tool) {
        throw "$ToolName was not found under Android build-tools."
    }
    return $tool.FullName
}

$repoRoot = Split-Path -Parent $PSScriptRoot
Set-Location $repoRoot

$javaHome = Resolve-JavaHome
$androidHome = Resolve-AndroidHome
$env:JAVA_HOME = $javaHome
$env:ANDROID_HOME = $androidHome

$gradlePath = Join-Path $repoRoot 'gradlew.bat'
$aaptPath = Find-FirstTool $androidHome 'aapt.exe'
$apksignerPath = Find-FirstTool $androidHome 'apksigner.bat'
$signingPropertiesPath = Join-Path $repoRoot 'argus-signing.local.properties'
$signingInitScript = Join-Path $PSScriptRoot 'new-argus-upload-keystore.ps1'

Require-Tool $gradlePath 'Gradle wrapper'
Require-Tool $aaptPath 'aapt'
Require-Tool $apksignerPath 'apksigner'
Require-Tool $signingInitScript 'Argus signing init script'

if (-not (Test-Path $signingPropertiesPath)) {
    if ($SkipSigningInitialization) {
        throw "Signing properties were not found: $signingPropertiesPath"
    }
    & $signingInitScript
    if ($LASTEXITCODE -ne 0) {
        throw "Signing initialization failed with exit code $LASTEXITCODE."
    }
}

$signingProperties = Read-Properties $signingPropertiesPath
foreach ($key in @(
    'QSFERA_RELEASE_KEYSTORE',
    'QSFERA_RELEASE_KEYSTORE_PASSWORD',
    'QSFERA_RELEASE_KEY_ALIAS',
    'QSFERA_RELEASE_KEY_PASSWORD'
)) {
    if (-not $signingProperties.ContainsKey($key) -or [string]::IsNullOrWhiteSpace($signingProperties[$key])) {
        throw "Signing property is missing: $key"
    }
}

$env:QSFERA_RELEASE_KEYSTORE = $signingProperties['QSFERA_RELEASE_KEYSTORE']
$env:QSFERA_RELEASE_KEYSTORE_PASSWORD = $signingProperties['QSFERA_RELEASE_KEYSTORE_PASSWORD']
$env:QSFERA_RELEASE_KEY_ALIAS = $signingProperties['QSFERA_RELEASE_KEY_ALIAS']
$env:QSFERA_RELEASE_KEY_PASSWORD = $signingProperties['QSFERA_RELEASE_KEY_PASSWORD']

& $gradlePath :qsferaApp:assembleOriginalRelease --console=plain
if ($LASTEXITCODE -ne 0) {
    throw "Gradle release build failed with exit code $LASTEXITCODE."
}

$outputMetadataPath = Join-Path $repoRoot 'qsferaApp\build\outputs\apk\original\release\output-metadata.json'
if (-not (Test-Path $outputMetadataPath)) {
    throw "Release output metadata was not found: $outputMetadataPath"
}

$outputMetadata = Get-Content $outputMetadataPath -Raw | ConvertFrom-Json
$outputFile = $outputMetadata.elements[0].outputFile
$releaseApkPath = Join-Path $repoRoot ("qsferaApp\build\outputs\apk\original\release\{0}" -f $outputFile)
if (-not (Test-Path $releaseApkPath)) {
    throw "Release APK was not found: $releaseApkPath"
}
if ($releaseApkPath -like '*-unsigned.apk') {
    throw "Release APK is unsigned: $releaseApkPath"
}

$badging = & $aaptPath dump badging $releaseApkPath
if ($LASTEXITCODE -ne 0) {
    throw "aapt badging failed with exit code $LASTEXITCODE."
}
$badgingText = ($badging | Out-String)
$packageName = Get-ApkBadgingValue $badgingText "package: name='([^']+)'"
$versionCode = Get-ApkBadgingValue $badgingText "versionCode='([^']+)'"
$versionName = Get-ApkBadgingValue $badgingText "versionName='([^']+)'"
$targetSdk = Get-ApkBadgingValue $badgingText "targetSdkVersion:'([^']+)'"
$applicationLabel = Get-ApkBadgingValue $badgingText "application-label:'([^']+)'"
$nativeCodeLine = ($badging | Where-Object { $_ -like 'native-code:*' } | Select-Object -First 1)
$nativeCodes = if ($nativeCodeLine) {
    [regex]::Matches($nativeCodeLine, "'([^']+)'") | ForEach-Object { $_.Groups[1].Value }
} else {
    @()
}
$detectedPlatform = Resolve-ArgusPlatform $nativeCodes
$resolvedPlatform = if ([string]::IsNullOrWhiteSpace($Platform)) {
    $detectedPlatform
} else {
    $Platform.Trim()
}

if (-not $packageName) {
    throw 'Package name could not be extracted from APK.'
}
if ($packageName -ne 'eu.qsfera.android') {
    throw "Unexpected package name: $packageName"
}
if (-not $versionCode) {
    throw 'Version code could not be extracted from APK.'
}
if (-not $versionName) {
    throw 'Version name could not be extracted from APK.'
}
if (-not $targetSdk) {
    throw 'Target SDK could not be extracted from APK.'
}

$certOutput = & $apksignerPath verify --print-certs $releaseApkPath
if ($LASTEXITCODE -ne 0) {
    throw "apksigner verification failed with exit code $LASTEXITCODE."
}
$certText = ($certOutput | Out-String)
$certificateSha256 = Get-ApkBadgingValue $certText "SHA-256 digest: ([0-9a-fA-F]+)"
if ($certText -match 'CN=Android Debug' -or $certificateSha256 -eq 'b86d745cecb01ca24bda03092fe94ca7801678513b97edd1175bcabfdea4e941') {
    throw 'Release APK is signed with the Android debug certificate.'
}

$resolvedName = if ($Name) { $Name } elseif ($applicationLabel) { $applicationLabel } else { 'QSfera' }
$releaseVersion = if ($Version) { $Version } else { $versionName }
$stageDirectory = Join-Path $repoRoot ("build\argus-publication\v{0}" -f $versionCode)
if (-not (Test-Path $stageDirectory)) {
    New-Item -ItemType Directory -Path $stageDirectory | Out-Null
}

$stagedApkName = "{0}-{1}.apk" -f $Slug, $versionCode
$stagedApkPath = Join-Path $stageDirectory $stagedApkName
Copy-Item $releaseApkPath $stagedApkPath -Force

$metadata = [ordered]@{
    packagePath = $stagedApkPath
    slug = $Slug
    name = $resolvedName
    summary = $Summary
    description = $Description
    version = $releaseVersion
    channel = $Channel
    platform = $resolvedPlatform
    packageKind = 'apk'
    notes = if ($Notes) { $Notes } else { $null }
    repositoryUrl = if ($RepositoryUrl) { $RepositoryUrl } else { $null }
    homepageUrl = if ($HomepageUrl) { $HomepageUrl } else { $null }
    androidPackageName = $packageName
    androidVersionCode = [int]$versionCode
    targetSdkVersion = [int]$targetSdk
    isListed = (-not $Unlisted)
    verifiedFromApk = [ordered]@{
        outputFile = $releaseApkPath
        packageName = $packageName
        versionCode = [int]$versionCode
        versionName = $versionName
        targetSdkVersion = [int]$targetSdk
        nativeCodes = $nativeCodes
        detectedPlatform = $detectedPlatform
        applicationLabel = if ($applicationLabel) { $applicationLabel } else { $null }
        certificateSha256 = $certificateSha256
        verifiedAt = [DateTimeOffset]::UtcNow.ToString('O')
    }
}

$metadataPath = Join-Path $stageDirectory 'argus-publication.json'
$metadata | ConvertTo-Json -Depth 6 | Set-Content -Path $metadataPath -Encoding UTF8

Write-Output 'Prepared QSfera Argus publication files.'
Write-Output "APK: $stagedApkPath"
Write-Output "Metadata: $metadataPath"
