
[CmdletBinding()]
param(
    [string]$Url = '',
    [switch]$ForceRefresh
)

$ErrorActionPreference = 'Stop'
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$MdkVersion = '0.37.0'

function Test-SevenZipArchive {
    param([string]$Path)
    if (-not (Test-Path $Path)) { return $false }
    $stream = [System.IO.File]::OpenRead($Path)
    try {
        if ($stream.Length -lt 6) { return $false }
        $buffer = New-Object byte[] 6
        [void]$stream.Read($buffer, 0, 6)
    } finally {
        $stream.Dispose()
    }
    $magic = 0x37, 0x7A, 0xBC, 0xAF, 0x27, 0x1C
    for ($i = 0; $i -lt 6; $i++) {
        if ($buffer[$i] -ne $magic[$i]) { return $false }
    }
    return $true
}

function Resolve-CMakeExecutable {
    $pathCommand = Get-Command 'cmake.exe' -ErrorAction SilentlyContinue
    if ($pathCommand) {
        return $pathCommand.Source
    }

    $visualStudioInstallations = @()
    $vswherePath = Join-Path ${Env:ProgramFiles(x86)} 'Microsoft Visual Studio\Installer\vswhere.exe'
    if (Test-Path $vswherePath) {
        $visualStudioInstallations += @(
            & $vswherePath -products '*' -property installationPath 2>$null
        )
    }

    foreach ($programFilesRoot in @($Env:ProgramFiles, ${Env:ProgramFiles(x86)})) {
        if (-not $programFilesRoot) { continue }
        foreach ($edition in @('BuildTools', 'Community', 'Professional', 'Enterprise')) {
            $visualStudioInstallations += Join-Path $programFilesRoot "Microsoft Visual Studio\2022\$edition"
        }
    }

    foreach ($installationPath in $visualStudioInstallations | Select-Object -Unique) {
        if (-not $installationPath) { continue }
        $candidate = Join-Path $installationPath 'Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe'
        if (Test-Path $candidate) {
            return $candidate
        }
    }

    $androidSdkRoots = @(
        $Env:ANDROID_SDK_ROOT,
        $Env:ANDROID_HOME,
        $(if ($Env:LOCALAPPDATA) { Join-Path $Env:LOCALAPPDATA 'Android\sdk' })
    ) | Where-Object { $_ -and (Test-Path $_) } | Select-Object -Unique

    foreach ($androidSdkRoot in $androidSdkRoots) {
        $cmakeRoot = Join-Path $androidSdkRoot 'cmake'
        if (-not (Test-Path $cmakeRoot)) { continue }
        $candidate = Get-ChildItem $cmakeRoot -Directory -ErrorAction SilentlyContinue |
            Sort-Object Name -Descending |
            ForEach-Object { Join-Path $_.FullName 'bin\cmake.exe' } |
            Where-Object { Test-Path $_ } |
            Select-Object -First 1
        if ($candidate) {
            return $candidate
        }
    }

    return $null
}

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

$PackageConfig = Join-Path $ProjectRoot '.dart_tool\package_config.json'
if (-not (Test-Path $PackageConfig)) {
    throw "package_config.json not found: $PackageConfig (run flutter pub get first)"
}

$config = Get-Content $PackageConfig -Raw | ConvertFrom-Json
$fvp = $config.packages | Where-Object { $_.name -eq 'fvp' } | Select-Object -First 1
if (-not $fvp) {
    throw 'Package fvp not found in .dart_tool/package_config.json'
}

$fvpRoot = [Uri]$fvp.rootUri
if (-not $fvpRoot.IsFile) {
    throw "Unsupported fvp rootUri: $($fvp.rootUri)"
}

$fvpWindowsDir = Join-Path $fvpRoot.LocalPath 'windows'
if (-not (Test-Path $fvpWindowsDir)) {
    throw "fvp windows directory not found: $fvpWindowsDir"
}

$sdkDir = Join-Path $fvpWindowsDir 'mdk-sdk'
$sdkVersionMarkerPath = Join-Path $sdkDir '.smplayer-mdk-version'
$archivePath = Join-Path $fvpWindowsDir "mdk-sdk-windows-x64-v$MdkVersion-vs2026.7z"

if ($ForceRefresh) {
    Write-Host "==> Force refreshing fvp mdk-sdk v$MdkVersion" -ForegroundColor Yellow
    if (Test-Path $sdkDir) {
        Remove-Item $sdkDir -Recurse -Force
    }
    if (Test-Path $archivePath) {
        Remove-Item $archivePath -Force
    }
}

if (Test-Path $sdkDir) {
    $installedMdkVersion = if (Test-Path $sdkVersionMarkerPath) {
        (Get-Content $sdkVersionMarkerPath -Raw).Trim()
    } else {
        ''
    }
    if ($installedMdkVersion -eq $MdkVersion) {
        Write-Host "==> fvp mdk-sdk v$MdkVersion already exists: $sdkDir" -ForegroundColor Green
        exit 0
    }

    $displayVersion = if ($installedMdkVersion) { $installedMdkVersion } else { 'unknown' }
    Write-Host "==> Replacing cached mdk-sdk v$displayVersion with v$MdkVersion" -ForegroundColor Yellow
    Remove-Item $sdkDir -Recurse -Force
}

$candidates = @()
if ($Url) {
    $candidates += $Url
} else {
    $candidates += "https://github.com/wang-bin/mdk-sdk/releases/download/v$MdkVersion/mdk-sdk-windows-x64-vs2026.7z"
}

if ((Test-Path $archivePath) -and -not (Test-SevenZipArchive $archivePath)) {
    Write-Host "==> Cached archive is not a valid 7z, removing: $archivePath" -ForegroundColor Yellow
    Remove-Item $archivePath -Force
}

if (-not (Test-Path $archivePath)) {
    $downloaded = $false
    :outer foreach ($candidate in $candidates) {
        $maxAttempts = 3
        for ($attempt = 1; $attempt -le $maxAttempts; $attempt++) {
            Write-Host "==> Downloading mdk-sdk (attempt $attempt/$maxAttempts): $candidate" -ForegroundColor Cyan
            try {
                Invoke-WebRequest -Uri $candidate -OutFile $archivePath `
                    -UseBasicParsing -MaximumRedirection 10 `
                    -UserAgent 'Mozilla/5.0' -TimeoutSec 120
            } catch {
                Write-Host "    download failed: $($_.Exception.Message)" -ForegroundColor Yellow
                if (Test-Path $archivePath) { Remove-Item $archivePath -Force }
                if ($attempt -lt $maxAttempts) {
                    $delay = $attempt * 10
                    Write-Host "    retrying in ${delay}s..." -ForegroundColor Yellow
                    Start-Sleep -Seconds $delay
                }
                continue
            }
            if (Test-SevenZipArchive $archivePath) {
                $downloaded = $true
                break outer
            }
            $size = (Get-Item $archivePath).Length
            Write-Host "    not a valid 7z archive (size=$size bytes), trying next" -ForegroundColor Yellow
            Remove-Item $archivePath -Force
            break  # bad content, skip retries for this URL
        }
    }
    if (-not $downloaded) {
        throw "Failed to download a valid mdk-sdk archive from: $($candidates -join ', ')"
    }
}

Write-Host "==> Extracting mdk-sdk to: $fvpWindowsDir" -ForegroundColor Cyan

$sevenZipCommand = Get-Command '7z.exe' -ErrorAction SilentlyContinue
$sevenZip = if ($sevenZipCommand) {
    $sevenZipCommand.Source
} else {
    @(
        "$Env:ProgramFiles\7-Zip\7z.exe",
        "${Env:ProgramFiles(x86)}\7-Zip\7z.exe"
    ) | Where-Object { Test-Path $_ } | Select-Object -First 1
}

if ($sevenZip) {
    & $sevenZip x '-y' "-o$fvpWindowsDir" $archivePath
} else {
    $cmakeExecutable = Resolve-CMakeExecutable
    if (-not $cmakeExecutable) {
        throw 'Neither 7-Zip nor CMake was found. Install the Visual Studio C++ CMake tools or 7-Zip, then retry.'
    }
    Write-Host "==> Using CMake: $cmakeExecutable" -ForegroundColor DarkGray
    Push-Location $fvpWindowsDir
    try {
        & $cmakeExecutable -E tar xvf $archivePath
    } finally {
        Pop-Location
    }
}

if ($LASTEXITCODE -ne 0) {
    throw "Failed to extract mdk-sdk (exit $LASTEXITCODE)"
}

if (-not (Test-Path $sdkDir)) {
    throw "mdk-sdk not found after extraction: $sdkDir"
}

Set-Content -Path $sdkVersionMarkerPath -Value $MdkVersion -NoNewline
Write-Host "==> fvp mdk-sdk v$MdkVersion ready: $sdkDir" -ForegroundColor Green
