# check-ffmpeg-update.ps1

[CmdletBinding()]
param(
    [string]$ReportPath,
    [switch]$FailIfUpdateAvailable,
    [string]$WorkRoot = 'C:\nnffb',
    [switch]$CreateCandidateLock,
    [switch]$AsJson
)

$ErrorActionPreference = 'Stop'
Set-StrictMode -Version Latest
Import-Module (Join-Path $PSScriptRoot 'BuildCommon.psm1') -Force

function Download-OfficialFfmpegFile {
    param([Parameter(Mandatory)][string]$Url, [Parameter(Mandatory)][string]$Destination)

    $uri = [Uri]$Url
    if ($uri.Scheme -ne 'https' -or $uri.Host -ne 'ffmpeg.org') {
        throw "Refusing candidate download from unexpected URL: $Url"
    }
    if (Test-Path $Destination) { return }

    $temporaryPath = "$Destination.download"
    if (Test-Path $temporaryPath) { Remove-Item -Force $temporaryPath }
    [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12
    Add-Type -AssemblyName System.Net.Http -ErrorAction Stop
    $handler = New-Object System.Net.Http.HttpClientHandler
    $handler.AllowAutoRedirect = $false
    $client = New-Object System.Net.Http.HttpClient($handler)
    try {
        $response = $client.GetAsync($uri, [System.Net.Http.HttpCompletionOption]::ResponseHeadersRead).GetAwaiter().GetResult()
        try {
            if ([int]$response.StatusCode -ne 200) {
                throw "FFmpeg candidate download returned HTTP $([int]$response.StatusCode): $Url"
            }
            $stream = [System.IO.File]::Create($temporaryPath)
            try { $response.Content.CopyToAsync($stream).GetAwaiter().GetResult() } finally { $stream.Close() }
        } finally {
            $response.Dispose()
        }
        Move-FileAtomically -Source $temporaryPath -Destination $Destination
    } finally {
        $client.Dispose()
        if (Test-Path $temporaryPath) { Remove-Item -Force $temporaryPath }
    }
}

function Assert-OfficialFfmpegSignature {
    param(
        [Parameter(Mandatory)]$CurrentComponent,
        [Parameter(Mandatory)][string]$TarballPath,
        [Parameter(Mandatory)][string]$SignaturePath,
        [Parameter(Mandatory)][string]$WorkRoot
    )

    $repoRoot = Get-RepoRoot
    $keyFile = Join-Path $repoRoot ($CurrentComponent.signature.keyFile -replace '/', '\\')
    if ((Get-FileSha256 $keyFile) -ne $CurrentComponent.signature.keyFileSha256.ToLowerInvariant()) {
        throw "Pinned FFmpeg release key hash mismatch: $keyFile"
    }
    $paths = Get-BuildPaths $WorkRoot
    $gpgExe = Join-Path $paths.msysRoot 'usr\bin\gpg.exe'
    if (-not (Test-Path $gpgExe)) {
        throw "MSYS2 gpg is not available at $gpgExe. Build the current pinned version first so the candidate can be PGP-verified."
    }

    $fingerprint = $CurrentComponent.signature.keyFingerprint.ToUpperInvariant()
    $command = "set -e; export GNUPGHOME=`$(mktemp -d); " +
        "gpg --batch --quiet --import '$(ConvertTo-MsysPath $keyFile)'; " +
        "gpg --batch --status-fd 1 --verify '$(ConvertTo-MsysPath $SignaturePath)' '$(ConvertTo-MsysPath $TarballPath)' 2>/dev/null"
    $output = @(Invoke-MsysCommand -MsysRoot $paths.msysRoot -Command $command) -join "`n"
    if ($output -notmatch [regex]::Escape($fingerprint) -or $output -notmatch '\[GNUPG:\] VALIDSIG ') {
        throw "Candidate FFmpeg signature did not verify under the pinned release key $fingerprint."
    }
}

$lock = Read-DependencyLock
$current = Get-LockComponent $lock 'ffmpeg'
$response = Invoke-WebRequest -Uri 'https://ffmpeg.org/download.html' -UseBasicParsing
$versions = @([regex]::Matches($response.Content, 'ffmpeg-(?<version>\d+\.\d+(?:\.\d+)?)\.tar\.xz') |
    ForEach-Object { $_.Groups['version'].Value } |
    Sort-Object -Unique |
    ForEach-Object { [version]$_ } |
    Sort-Object -Descending)

if ($versions.Count -eq 0) {
    throw 'Could not find a stable FFmpeg source release on https://ffmpeg.org/download.html.'
}

$latest = $versions[0].ToString()
$updateAvailable = [version]$latest -gt [version]$current.version
$report = [ordered]@{
    checkedUtc = (Get-Date).ToUniversalTime().ToString('o')
    currentPinnedVersion = $current.version
    latestOfficialVersion = $latest
    updateAvailable = $updateAvailable
    sourcePage = 'https://ffmpeg.org/download.html'
    candidateTarballUrl = "https://ffmpeg.org/releases/ffmpeg-$latest.tar.xz"
    candidateSignatureUrl = "https://ffmpeg.org/releases/ffmpeg-$latest.tar.xz.asc"
    candidateLockPath = $null
    nextStep = if ($updateAvailable) {
        'Create a review branch, update dependencies.lock.json with the new URL and independently verified tarball/signature SHA-256 values, then run an unsigned candidate build. Do not publish embedded assets until qualification is complete.'
    } else {
        'The current pinned FFmpeg release is the latest official stable release.'
    }
}

if ($CreateCandidateLock -and $updateAvailable) {
    Assert-WorkRoot $WorkRoot
    $repoRoot = Get-RepoRoot
    $candidateDownloadDirectory = Join-Path $WorkRoot "candidate-pins\ffmpeg-$latest"
    New-Item -ItemType Directory -Force -Path $candidateDownloadDirectory | Out-Null
    $tarballPath = Join-Path $candidateDownloadDirectory "ffmpeg-$latest.tar.xz"
    $signaturePath = Join-Path $candidateDownloadDirectory "ffmpeg-$latest.tar.xz.asc"
    Download-OfficialFfmpegFile -Url $report.candidateTarballUrl -Destination $tarballPath
    Download-OfficialFfmpegFile -Url $report.candidateSignatureUrl -Destination $signaturePath
    Assert-OfficialFfmpegSignature -CurrentComponent $current -TarballPath $tarballPath -SignaturePath $signaturePath -WorkRoot $WorkRoot

    $candidateLock = $lock | ConvertTo-Json -Depth 12 | ConvertFrom-Json
    $candidate = Get-LockComponent $candidateLock 'ffmpeg'
    $candidate.version = $latest
    $candidate.url = $report.candidateTarballUrl
    $candidate.filename = "ffmpeg-$latest.tar.xz"
    $candidate.sha256 = Get-FileSha256 $tarballPath
    $candidate.extractedRoot = "ffmpeg-$latest"
    $candidate.reason = "Candidate FFmpeg $latest from the official release page, downloaded and PGP-verified on $((Get-Date).ToUniversalTime().ToString('yyyy-MM-dd')). Review and test before promoting."
    $candidate.signature.url = $report.candidateSignatureUrl
    $candidate.signature.filename = "ffmpeg-$latest.tar.xz.asc"
    $candidate.signature.sha256 = Get-FileSha256 $signaturePath

    $candidateLockPath = Join-Path $repoRoot "config\candidates\dependencies.lock.ffmpeg-$latest.json"
    Write-JsonFile -Object $candidateLock -Path $candidateLockPath -Depth 12
    $report.candidateLockPath = $candidateLockPath
    $report.candidateTarballSha256 = $candidate.sha256
    $report.candidateSignatureSha256 = $candidate.signature.sha256
    $report.nextStep = 'Select this separately verified candidate lock in Release Manager and run an unsigned candidate build. The production dependency lock and application assets remain unchanged.'
}

if ($ReportPath) {
    Write-JsonFile -Object $report -Path $ReportPath
    Write-Host "Update report: $ReportPath" -ForegroundColor Green
}

$report | ForEach-Object {
    if ($AsJson) { $_ | ConvertTo-Json -Depth 12 -Compress } else { $_ }
}
if ($FailIfUpdateAvailable -and $updateAvailable) {
    throw "FFmpeg $latest is newer than the pinned $($current.version)."
}
