<#
.SYNOPSIS
Builds, verifies, and installs a signed Memby release on an Android TV.

.DESCRIPTION
Uses the permanent signing configuration stored in the current Windows user's
MEMBY_KEYSTORE environment variables. The APK is installed directly with ADB;
no Gitea release or update server is required.

.EXAMPLE
.\deploy-tv.ps1

.EXAMPLE
.\deploy-tv.ps1 -Device 10.0.0.238:35343 -SkipTests
#>

#Requires -Version 7.2

[CmdletBinding()]
param(
    [Parameter()]
    [ValidatePattern('^[A-Za-z0-9._:-]+$')]
    [string] $Device = '10.0.0.238:35343',

    [Parameter()]
    [switch] $SkipTests
)

Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'

$root = $PSScriptRoot
$packageName = 'com.ponzischeme89.memby'

function Invoke-Checked {
    param(
        [Parameter(Mandatory)]
        [string] $FilePath,

        [Parameter()]
        [string[]] $Arguments = @()
    )

    & $FilePath @Arguments
    if ($LASTEXITCODE -ne 0) {
        throw "'$FilePath' failed with exit code $LASTEXITCODE."
    }
}

function Get-AndroidSdk {
    if ($env:ANDROID_HOME -and (Test-Path -LiteralPath $env:ANDROID_HOME)) {
        return $env:ANDROID_HOME
    }

    $propertiesPath = Join-Path $root 'local.properties'
    if (Test-Path -LiteralPath $propertiesPath) {
        $sdkLine = Get-Content -LiteralPath $propertiesPath |
            Where-Object { $_ -match '^sdk\.dir=' } |
            Select-Object -First 1
        if ($sdkLine) {
            $sdkPath = $sdkLine.Substring($sdkLine.IndexOf('=') + 1).
                Replace('\:', ':').
                Replace('\\', '\')
            if (Test-Path -LiteralPath $sdkPath) {
                return $sdkPath
            }
        }
    }

    throw 'Android SDK not found. Set ANDROID_HOME or sdk.dir in local.properties.'
}

function Import-UserSigningEnvironment {
    foreach ($name in @(
        'MEMBY_KEYSTORE',
        'MEMBY_KEYSTORE_PASSWORD',
        'MEMBY_KEY_ALIAS',
        'MEMBY_KEY_PASSWORD'
    )) {
        $value = [Environment]::GetEnvironmentVariable($name, 'Process')
        if ([string]::IsNullOrWhiteSpace($value)) {
            $value = [Environment]::GetEnvironmentVariable($name, 'User')
        }
        if ([string]::IsNullOrWhiteSpace($value)) {
            throw "Release signing variable $name is not configured."
        }
        [Environment]::SetEnvironmentVariable($name, $value, 'Process')
    }

    if (-not (Test-Path -LiteralPath $env:MEMBY_KEYSTORE -PathType Leaf)) {
        throw "Release keystore not found: $env:MEMBY_KEYSTORE"
    }
}

Write-Host ''
Write-Host '╭─ Memby TV deployment' -ForegroundColor Magenta
Write-Host "│  Device  $Device" -ForegroundColor DarkGray
Write-Host '│  Build   signed release' -ForegroundColor DarkGray
Write-Host '╰─' -ForegroundColor Magenta
Write-Host ''

Import-UserSigningEnvironment
$sdk = Get-AndroidSdk
$adb = Join-Path $sdk 'platform-tools\adb.exe'
if (-not (Test-Path -LiteralPath $adb -PathType Leaf)) {
    throw "ADB not found: $adb"
}

$buildTools = Get-ChildItem -LiteralPath (Join-Path $sdk 'build-tools') -Directory |
    Sort-Object { [version]$_.Name } -Descending |
    Select-Object -First 1
if (-not $buildTools) {
    throw 'Android SDK Build Tools are not installed.'
}
$apkSigner = Join-Path $buildTools.FullName 'apksigner.bat'
if (-not (Test-Path -LiteralPath $apkSigner -PathType Leaf)) {
    throw "APK signer not found: $apkSigner"
}

$jdkHome = 'C:\Program Files\Android\Android Studio\jbr'
if (Test-Path -LiteralPath $jdkHome) {
    $env:JAVA_HOME = $jdkHome
}

Write-Host '● Building release APK' -ForegroundColor Cyan
$gradleArguments = @('--console=plain')
if (-not $SkipTests) {
    $gradleArguments += 'testDebugUnitTest'
}
$gradleArguments += 'assembleRelease'
Invoke-Checked -FilePath (Join-Path $root 'gradlew.bat') -Arguments $gradleArguments

$apk = Join-Path $root 'app\build\outputs\apk\release\app-release.apk'
if (-not (Test-Path -LiteralPath $apk -PathType Leaf)) {
    $unsigned = Join-Path $root 'app\build\outputs\apk\release\app-release-unsigned.apk'
    if (Test-Path -LiteralPath $unsigned) {
        throw 'Gradle produced an unsigned APK; deployment was stopped.'
    }
    throw "Release APK not found: $apk"
}

Write-Host ''
Write-Host '● Verifying release signature' -ForegroundColor Cyan
Invoke-Checked -FilePath $apkSigner -Arguments @(
    'verify',
    '--verbose',
    '--print-certs',
    $apk
)

Write-Host ''
Write-Host '● Connecting to Android TV' -ForegroundColor Cyan
& $adb connect $Device
if ($LASTEXITCODE -ne 0) {
    throw "Unable to connect to Android TV at $Device."
}
Invoke-Checked -FilePath $adb -Arguments @('-s', $Device, 'get-state')

Write-Host ''
Write-Host '● Installing release' -ForegroundColor Cyan
Invoke-Checked -FilePath $adb -Arguments @(
    '-s', $Device,
    'install',
    '-r',
    '--no-streaming',
    $apk
)

$packageDetails = & $adb -s $Device shell dumpsys package $packageName
if ($LASTEXITCODE -ne 0) {
    throw 'The APK installed, but its package details could not be read.'
}
$versionName = (
    $packageDetails |
        Select-String -Pattern 'versionName=([^\s]+)' |
        Select-Object -First 1
).Matches.Groups[1].Value
if ([string]::IsNullOrWhiteSpace($versionName)) {
    throw "Installed package $packageName was not found."
}

$resolveOutput = & $adb -s $Device shell cmd package resolve-activity --brief `
    -a android.intent.action.MAIN `
    -c android.intent.category.LEANBACK_LAUNCHER `
    $packageName
$component = $resolveOutput |
    Where-Object { $_.Trim() -match '^[A-Za-z0-9._]+/[A-Za-z0-9._$]+$' } |
    Select-Object -Last 1
if ($LASTEXITCODE -eq 0 -and $component) {
    $component = $component.Trim()
    Invoke-Checked -FilePath $adb -Arguments @(
        '-s', $Device,
        'shell', 'am', 'start',
        '-n', $component
    )
}

Write-Host ''
Write-Host "✓ Memby $versionName installed on $Device" -ForegroundColor Green
Write-Host "  Package: $packageName" -ForegroundColor DarkGray
Write-Host "  APK:     $apk" -ForegroundColor DarkGray
