# RescuePC Protected Module - DO NOT EDIT
# Source code is maintained separately in the development repository.

$script:UpdateConfig = @{
    PackApiUrl = "https://www.rescuepcrepairs.com/api/packs/latest"

    PacksDirectory = "$env:LOCALAPPDATA\RescuePC\Packs"
    BackupDirectory = "$env:LOCALAPPDATA\RescuePC\Packs\Backup"
    TempDirectory = "$env:TEMP\RescuePC_PackUpdate"
    VersionFile = "$env:LOCALAPPDATA\RescuePC\pack-version.json"

    CheckIntervalHours = 6
    MaxBackups = 3
    TimeoutSeconds = 30

    MaxRetries = 3
    RetryDelaySeconds = 5
}

function Get-LocalPackVersion {
    [CmdletBinding()]
    param(
        [string]$PackPath = ""
    )

    if (-not $PackPath) {
        $PackPath = $script:UpdateConfig.PacksDirectory
    }

    $versionFile = Join-Path $PackPath "pack-version.json"
    if (Test-Path $versionFile) {
        try {
            $version = Get-Content -Path $versionFile -Raw | ConvertFrom-Json
            return $version
        }
        catch { }
    }

    $manifestPath = Join-Path $PackPath "pack-manifest.json"
    if (Test-Path $manifestPath) {
        try {
            $manifest = Get-Content -Path $manifestPath -Raw | ConvertFrom-Json
            return @{
                Version = $manifest.PackVersion
                InstalledAt = (Get-Item $manifestPath).LastWriteTime.ToString("o")
            }
        }
        catch { }
    }

    return @{
        Version = "0.0.0"
        InstalledAt = $null
    }
}

function Compare-PackVersions {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [string]$Version1,

        [Parameter(Mandatory)]
        [string]$Version2
    )

    try {
        $v1 = [Version]$Version1
        $v2 = [Version]$Version2
        return $v1.CompareTo($v2)
    }
    catch {
        return [string]::Compare($Version1, $Version2)
    }
}

function Test-PackUpdateAvailable {
    [CmdletBinding()]
    param(
        [string]$LicenseKey = "",
        [switch]$Force
    )

    $result = @{
        UpdateAvailable = $false
        CurrentVersion = "0.0.0"
        LatestVersion = "0.0.0"
        DownloadUrl = ""
        Sha256 = ""
        Changelog = @()
        Error = $null
    }

    try {
        if (-not $Force) {
            $lastCheckFile = Join-Path $env:LOCALAPPDATA "RescuePC\last-update-check.txt"
            if (Test-Path $lastCheckFile) {
                $lastCheck = Get-Content $lastCheckFile -Raw
                $lastCheckTime = [DateTime]::Parse($lastCheck)
                $hoursSinceCheck = ((Get-Date) - $lastCheckTime).TotalHours

                if ($hoursSinceCheck -lt $script:UpdateConfig.CheckIntervalHours) {
                    $result.Error = "Skipped - checked $([math]::Round($hoursSinceCheck, 1)) hours ago"
                    return $result
                }
            }
        }

        $localVersion = Get-LocalPackVersion
        $result.CurrentVersion = $localVersion.Version

        $headers = @{
            "User-Agent" = "RescuePC-Updater/1.0"
            "Accept" = "application/json"
        }

        if ($LicenseKey) {
            $headers["x-license-key"] = $LicenseKey
        }

        $response = Invoke-RestMethod -Uri $script:UpdateConfig.PackApiUrl `
            -Method Get `
            -Headers $headers `
            -TimeoutSec $script:UpdateConfig.TimeoutSeconds `
            -ErrorAction Stop

        if ($response.success -and $response.pack) {
            $pack = $response.pack
            $result.LatestVersion = $pack.version
            $result.DownloadUrl = $pack.url
            $result.Sha256 = $pack.sha256
            $result.Changelog = $pack.changelog

            $comparison = Compare-PackVersions -Version1 $pack.version -Version2 $localVersion.Version
            $result.UpdateAvailable = ($comparison -gt 0)
        }

        $checkDir = Split-Path $lastCheckFile -Parent
        if (-not (Test-Path $checkDir)) {
            New-Item -ItemType Directory -Path $checkDir -Force | Out-Null
        }
        (Get-Date).ToString("o") | Out-File $lastCheckFile -Encoding UTF8 -Force

    }
    catch {
        $result.Error = $_.Exception.Message
    }

    return $result
}

function Get-PackUpdate {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [string]$DownloadUrl,

        [Parameter(Mandatory)]
        [string]$ExpectedSha256,

        [string]$PublicKeyPath = ""
    )

    $result = @{
        Success = $false
        TempPath = ""
        ExtractPath = ""
        Error = $null
    }

    $tempDir = $script:UpdateConfig.TempDirectory
    if (Test-Path $tempDir) {
        Remove-Item -Path $tempDir -Recurse -Force -ErrorAction SilentlyContinue
    }
    New-Item -ItemType Directory -Path $tempDir -Force | Out-Null

    $zipPath = Join-Path $tempDir "pack-update.zip"
    $extractPath = Join-Path $tempDir "extracted"

    try {
        Write-Host "Downloading pack update..." -ForegroundColor Yellow

        $downloaded = $false
        for ($i = 1; $i -le $script:UpdateConfig.MaxRetries; $i++) {
            try {
                $webClient = New-Object System.Net.WebClient
                $webClient.Headers.Add("User-Agent", "RescuePC-Updater/1.0")
                $webClient.DownloadFile($DownloadUrl, $zipPath)
                $downloaded = $true
                break
            }
            catch {
                if ($i -lt $script:UpdateConfig.MaxRetries) {
                    Write-Host "  Retry $i/$($script:UpdateConfig.MaxRetries)..." -ForegroundColor Gray
                    Start-Sleep -Seconds $script:UpdateConfig.RetryDelaySeconds
                }
            }
        }

        if (-not $downloaded) {
            throw "Failed to download pack after $($script:UpdateConfig.MaxRetries) attempts"
        }

        Write-Host "  Downloaded: $(((Get-Item $zipPath).Length / 1KB).ToString('N0')) KB" -ForegroundColor Gray

        Write-Host "Verifying download integrity..." -ForegroundColor Yellow
        $actualHash = (Get-FileHash -Path $zipPath -Algorithm SHA256).Hash.ToLower()
        $expectedHash = $ExpectedSha256.ToLower()

        if ($actualHash -ne $expectedHash) {
            throw "SHA256 mismatch! Expected: $expectedHash, Got: $actualHash"
        }
        Write-Host "  SHA256 verified" -ForegroundColor Green

        Write-Host "Extracting pack..." -ForegroundColor Yellow
        New-Item -ItemType Directory -Path $extractPath -Force | Out-Null
        Expand-Archive -Path $zipPath -DestinationPath $extractPath -Force
        Write-Host "  Extracted to temp folder" -ForegroundColor Green

        Write-Host "Verifying pack signature..." -ForegroundColor Yellow

        $manifestPath = Join-Path $extractPath "pack-manifest.json"
        $signaturePath = Join-Path $extractPath "pack-signature.json"

        if (-not (Test-Path $manifestPath)) {
            throw "Pack is missing manifest file"
        }

        if (-not (Test-Path $signaturePath)) {
            throw "Pack is missing signature file"
        }

        if (Get-Command Test-PackSignature -ErrorAction SilentlyContinue) {
            $sigResult = Test-PackSignature -PackPath $extractPath -PublicKeyPath $PublicKeyPath

            if (-not $sigResult.Valid) {
                throw "Pack signature verification failed: $($sigResult.Error)"
            }
            Write-Host "  RSA-SHA256 signature verified" -ForegroundColor Green
            Write-Host "  Signed by: $($sigResult.SignedBy)" -ForegroundColor Gray
        }
        else {
            Write-Host "  [WARN] PackSigning module not loaded - skipping signature check" -ForegroundColor Yellow
        }

        $result.Success = $true
        $result.TempPath = $zipPath
        $result.ExtractPath = $extractPath

    }
    catch {
        $result.Error = $_.Exception.Message

        if (Test-Path $tempDir) {
            Remove-Item -Path $tempDir -Recurse -Force -ErrorAction SilentlyContinue
        }
    }

    return $result
}

function Install-PackUpdate {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [string]$ExtractPath,

        [string]$TargetPath = ""
    )

    if (-not $TargetPath) {
        $TargetPath = $script:UpdateConfig.PacksDirectory
    }

    $result = @{
        Success = $false
        BackupPath = ""
        Error = $null
    }

    $backupDir = $script:UpdateConfig.BackupDirectory
    $timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
    $backupPath = Join-Path $backupDir "pack_backup_$timestamp"

    try {
        if (-not (Test-Path $backupDir)) {
            New-Item -ItemType Directory -Path $backupDir -Force | Out-Null
        }

        Write-Host "Installing pack update..." -ForegroundColor Yellow

        if (Test-Path $TargetPath) {
            Write-Host "  Backing up current pack..." -ForegroundColor Gray

            $robocopyResult = robocopy $TargetPath $backupPath /E /NFL /NDL /NJH /NJS /NC /NS /NP 2>&1

            if (-not (Test-Path $backupPath)) {
                throw "Failed to create backup"
            }

            $result.BackupPath = $backupPath
            Write-Host "  Backup created: $backupPath" -ForegroundColor Gray
        }

        Write-Host "  Installing new pack..." -ForegroundColor Gray

        if (Test-Path $TargetPath) {
            Get-ChildItem -Path $TargetPath -Recurse | Remove-Item -Recurse -Force -ErrorAction Stop
        }
        else {
            New-Item -ItemType Directory -Path $TargetPath -Force | Out-Null
        }

        Copy-Item -Path "$ExtractPath\*" -Destination $TargetPath -Recurse -Force -ErrorAction Stop

        $manifestPath = Join-Path $TargetPath "pack-manifest.json"
        if (-not (Test-Path $manifestPath)) {
            throw "Installation verification failed - manifest not found"
        }

        $manifest = Get-Content -Path $manifestPath -Raw | ConvertFrom-Json
        $versionInfo = @{
            Version = $manifest.PackVersion
            InstalledAt = (Get-Date).ToString("o")
            PreviousVersion = if ($result.BackupPath) {
                (Get-LocalPackVersion -PackPath $result.BackupPath).Version
            } else { "0.0.0" }
        }

        $versionFile = Join-Path $TargetPath "pack-version.json"
        $versionInfo | ConvertTo-Json | Out-File $versionFile -Encoding UTF8 -Force

        Write-Host "  Pack installed successfully!" -ForegroundColor Green
        Write-Host "  Version: $($manifest.PackVersion)" -ForegroundColor Gray
        Write-Host "  Files: $($manifest.TotalFiles)" -ForegroundColor Gray

        $backups = Get-ChildItem -Path $backupDir -Directory |
            Where-Object { $_.Name -like "pack_backup_*" } |
            Sort-Object CreationTime -Descending |
            Select-Object -Skip $script:UpdateConfig.MaxBackups

        foreach ($oldBackup in $backups) {
            Remove-Item -Path $oldBackup.FullName -Recurse -Force -ErrorAction SilentlyContinue
        }

        $result.Success = $true

    }
    catch {
        $result.Error = $_.Exception.Message

        if ($result.BackupPath -and (Test-Path $result.BackupPath)) {
            Write-Host "  [ERROR] Installation failed, rolling back..." -ForegroundColor Red

            try {
                if (Test-Path $TargetPath) {
                    Remove-Item -Path $TargetPath -Recurse -Force -ErrorAction SilentlyContinue
                }

                Copy-Item -Path "$($result.BackupPath)\*" -Destination $TargetPath -Recurse -Force
                Write-Host "  Rollback successful" -ForegroundColor Yellow
            }
            catch {
                Write-Host "  [CRITICAL] Rollback failed: $($_.Exception.Message)" -ForegroundColor Red
            }
        }
    }
    finally {
        $tempDir = $script:UpdateConfig.TempDirectory
        if (Test-Path $tempDir) {
            Remove-Item -Path $tempDir -Recurse -Force -ErrorAction SilentlyContinue
        }
    }

    return $result
}

function Update-RescuePCPack {
    [CmdletBinding()]
    param(
        [string]$LicenseKey = "",
        [string]$PublicKeyPath = "",
        [switch]$Force,
        [switch]$Silent
    )

    $result = @{
        Success = $false
        Updated = $false
        CurrentVersion = "0.0.0"
        NewVersion = "0.0.0"
        Error = $null
    }

    try {
        if (-not $Silent) {
            Write-Host ""
            Write-Host "================================================================" -ForegroundColor Cyan
            Write-Host " RESCUEPC PACK UPDATE CHECK" -ForegroundColor Cyan
            Write-Host "================================================================" -ForegroundColor Cyan
            Write-Host ""
        }

        if (-not $Silent) { Write-Host "[1/3] Checking for updates..." -ForegroundColor Yellow }

        $updateCheck = Test-PackUpdateAvailable -LicenseKey $LicenseKey -Force:$Force
        $result.CurrentVersion = $updateCheck.CurrentVersion

        if ($updateCheck.Error -and $updateCheck.Error -like "Skipped*") {
            if (-not $Silent) { Write-Host "  $($updateCheck.Error)" -ForegroundColor Gray }
            $result.Success = $true
            return $result
        }

        if ($updateCheck.Error) {
            throw "Update check failed: $($updateCheck.Error)"
        }

        if (-not $updateCheck.UpdateAvailable) {
            if (-not $Silent) {
                Write-Host "  Current version: $($updateCheck.CurrentVersion)" -ForegroundColor Gray
                Write-Host "  Latest version:  $($updateCheck.LatestVersion)" -ForegroundColor Gray
                Write-Host "  [OK] Already up to date!" -ForegroundColor Green
            }
            $result.Success = $true
            return $result
        }

        if (-not $Silent) {
            Write-Host "  Current version: $($updateCheck.CurrentVersion)" -ForegroundColor Gray
            Write-Host "  Latest version:  $($updateCheck.LatestVersion)" -ForegroundColor Green
            Write-Host "  Update available!" -ForegroundColor Green

            if ($updateCheck.Changelog.Count -gt 0) {
                Write-Host "  Changelog:" -ForegroundColor Gray
                foreach ($change in $updateCheck.Changelog) {
                    Write-Host "    - $change" -ForegroundColor Gray
                }
            }
        }

        if (-not $Silent) { Write-Host "[2/3] Downloading update..." -ForegroundColor Yellow }

        $download = Get-PackUpdate -DownloadUrl $updateCheck.DownloadUrl `
            -ExpectedSha256 $updateCheck.Sha256 `
            -PublicKeyPath $PublicKeyPath

        if (-not $download.Success) {
            throw "Download failed: $($download.Error)"
        }

        if (-not $Silent) { Write-Host "[3/3] Installing update..." -ForegroundColor Yellow }

        $install = Install-PackUpdate -ExtractPath $download.ExtractPath

        if (-not $install.Success) {
            throw "Installation failed: $($install.Error)"
        }

        $result.Success = $true
        $result.Updated = $true
        $result.NewVersion = $updateCheck.LatestVersion

        if (-not $Silent) {
            Write-Host ""
            Write-Host "================================================================" -ForegroundColor Green
            Write-Host " UPDATE COMPLETE!" -ForegroundColor Green
            Write-Host " Version: $($updateCheck.CurrentVersion) -> $($updateCheck.LatestVersion)" -ForegroundColor Green
            Write-Host "================================================================" -ForegroundColor Green
            Write-Host ""
        }

    }
    catch {
        $result.Error = $_.Exception.Message
        if (-not $Silent) {
            Write-Host ""
            Write-Host "[ERROR] Update failed: $($_.Exception.Message)" -ForegroundColor Red
            Write-Host ""
        }
    }

    return $result
}

Export-ModuleMember -Function @(
    'Get-LocalPackVersion',
    'Compare-PackVersions',
    'Test-PackUpdateAvailable',
    'Get-PackUpdate',
    'Install-PackUpdate',
    'Update-RescuePCPack'
)