[CmdletBinding()]
param()

Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
Add-Type -AssemblyName System.Drawing

$root = $PSScriptRoot
$work = Join-Path $root 'work'
$screenshots = Join-Path $root 'screenshots'
New-Item -ItemType Directory -Path $screenshots -Force | Out-Null

function New-Brush([string] $Hex) {
    [System.Drawing.SolidBrush]::new([System.Drawing.ColorTranslator]::FromHtml($Hex))
}

function Save-Image([System.Drawing.Bitmap] $Bitmap, [string] $Path) {
    $Bitmap.Save($Path, [System.Drawing.Imaging.ImageFormat]::Png)
}

function New-TerminalEvidence {
    param(
        [Parameter(Mandatory)] [string] $Path,
        [Parameter(Mandatory)] [string] $Title,
        [Parameter(Mandatory)] [AllowEmptyString()] [string[]] $Lines,
        [ValidateSet('Pass', 'Deny', 'Info')] [string] $Tone = 'Info'
    )

    $bitmap = [System.Drawing.Bitmap]::new(1600, 900)
    $graphics = [System.Drawing.Graphics]::FromImage($bitmap)
    try {
        $graphics.SmoothingMode = 'AntiAlias'
        $graphics.TextRenderingHint = 'ClearTypeGridFit'
        $graphics.Clear([System.Drawing.ColorTranslator]::FromHtml('#060b14'))

        $header = New-Brush '#101928'
        $panel = New-Brush '#0a1320'
        $white = New-Brush '#eaf6ff'
        $muted = New-Brush '#8ca7b8'
        $accentHex = switch ($Tone) { 'Pass' { '#50f0ae' } 'Deny' { '#ff5d8f' } default { '#50d9ff' } }
        $accent = New-Brush $accentHex
        $magenta = New-Brush '#ff5dca'
        $border = [System.Drawing.Pen]::new([System.Drawing.ColorTranslator]::FromHtml('#37d9ff'), 2)
        $titleFont = [System.Drawing.Font]::new('Segoe UI Semibold', 31)
        $monoFont = [System.Drawing.Font]::new('Cascadia Mono', 23)
        $smallFont = [System.Drawing.Font]::new('Segoe UI', 17)
        try {
            $graphics.FillRectangle($header, 0, 0, 1600, 112)
            $graphics.FillEllipse((New-Brush '#ff5f57'), 42, 43, 24, 24)
            $graphics.FillEllipse((New-Brush '#febc2e'), 82, 43, 24, 24)
            $graphics.FillEllipse((New-Brush '#28c840'), 122, 43, 24, 24)
            $graphics.DrawString($Title, $titleFont, $white, 190, 31)
            $graphics.FillRectangle($panel, 36, 144, 1528, 700)
            $graphics.DrawRectangle($border, 36, 144, 1528, 700)
            $graphics.DrawString('pwsh 7.6  •  Azure CLI 2.88  •  sanitized Workshopz evidence', $smallFont, $muted, 62, 166)
            $y = 225
            foreach ($line in $Lines) {
                $lineBrush = if ($line -match 'PASS|PASSED|HTTP 200|match: true|exit code: 0|remaining: 0|unchanged: true') {
                    $accent
                }
                elseif ($line -match 'HTTP 403|DENIED|blocked') {
                    $magenta
                }
                else {
                    $white
                }
                $graphics.DrawString($line, $monoFont, $lineBrush, 68, $y)
                $y += 52
            }
            $graphics.DrawString('IDs, IP addresses, DNS names, emails, tokens, SSH material, and local paths are redacted.', $smallFont, $muted, 62, 806)
            Save-Image -Bitmap $bitmap -Path $Path
        }
        finally {
            foreach ($item in @($header, $panel, $white, $muted, $accent, $magenta, $border, $titleFont, $monoFont, $smallFont)) {
                $item.Dispose()
            }
        }
    }
    finally {
        $graphics.Dispose()
        $bitmap.Dispose()
    }
}

function Protect-PortalEvidence {
    param(
        [Parameter(Mandatory)] [string] $Source,
        [Parameter(Mandatory)] [string] $Destination,
        [Parameter(Mandatory)] [System.Drawing.Rectangle[]] $Redactions,
        [Parameter(Mandatory)] [string[]] $Labels
    )

    $sourceBitmap = [System.Drawing.Bitmap]::FromFile($Source)
    try {
        $bitmap = [System.Drawing.Bitmap]::new($sourceBitmap.Width, $sourceBitmap.Height)
        $graphics = [System.Drawing.Graphics]::FromImage($bitmap)
        try {
            $graphics.DrawImage($sourceBitmap, 0, 0, $sourceBitmap.Width, $sourceBitmap.Height)
            $mask = New-Brush '#242424'
            $text = New-Brush '#bfefff'
            $font = [System.Drawing.Font]::new('Segoe UI Semibold', 11)
            try {
                for ($index = 0; $index -lt $Redactions.Count; $index++) {
                    $rectangle = $Redactions[$index]
                    $graphics.FillRectangle($mask, $rectangle)
                    if ($index -lt $Labels.Count) {
                        $graphics.DrawString($Labels[$index], $font, $text, $rectangle.X + 5, $rectangle.Y + 4)
                    }
                }
                Save-Image -Bitmap $bitmap -Path $Destination
            }
            finally {
                $mask.Dispose()
                $text.Dispose()
                $font.Dispose()
            }
        }
        finally {
            $graphics.Dispose()
            $bitmap.Dispose()
        }
    }
    finally {
        $sourceBitmap.Dispose()
    }
}

function Read-Result([string] $Name) {
    $path = Join-Path $work $Name
    if (-not (Test-Path -LiteralPath $path)) { return $null }
    Get-Content -Raw -LiteralPath $path | ConvertFrom-Json -Depth 100
}

$preflight = Read-Result 'result-preflight.json'
if ($preflight) {
    New-TerminalEvidence -Path (Join-Path $screenshots '01-cli-preflight-safety-gate.png') -Title 'Stage 1 — Read-only preflight and safety gate' -Tone Pass -Lines @(
        'AZURE NETWORK SECURITY PERIMETER PREFLIGHT — PASSED',
        "Azure mutations performed: $($preflight.azureMutations)",
        "Owner effective: $($preflight.owner)",
        "User Access Administrator effective: $($preflight.userAccessAdministrator)",
        "Required providers registered: $($preflight.requiredProvidersRegistered)",
        "Namespace collisions: $($preflight.namespaceCollisions)",
        "Soft-deleted vault collisions: $($preflight.softDeletedVaultCollisions)",
        'Safety gate: PASS'
    )
}

$transition = Read-Result 'result-transition-seed.json'
if ($transition) {
    New-TerminalEvidence -Path (Join-Path $screenshots '03-cli-transition-managed-identity-success.png') -Title 'Stage 3 — Managed identity in Learning / Transition mode' -Tone Pass -Lines @(
        'NSP access rule present: no',
        "Blob write HTTP: $($transition.blobPutHttp)",
        "Storage read HTTP: $($transition.storageHttp)",
        "Key Vault write HTTP: $($transition.secretPutHttp)",
        "Key Vault read HTTP: $($transition.keyVaultHttp)",
        "Blob digest match: $([bool]$transition.storageContentMatch)",
        "Secret value match: $([bool]$transition.keyVaultValueMatch)",
        'Transition data-plane test: PASS'
    )
}

$logs = Read-Result 'result-querylogs.json'
if ($logs -and @($logs.rows).Count -gt 0) {
    $transitionRows = @($logs.rows | Where-Object { $_.category -eq 'NspPublicInboundResourceRulesAllowed' })
    New-TerminalEvidence -Path (Join-Path $screenshots '05-cli-transition-nsp-access-logs.png') -Title 'Stage 3 — NSPAccessLogs Transition fallback' -Tone Pass -Lines @(
        'Table: NSPAccessLogs',
        'Category: NspPublicInboundResourceRulesAllowed',
        "Storage events: $((@($transitionRows | Where-Object service -eq 'Storage').events | Measure-Object -Sum).Sum)",
        "Key Vault events: $((@($transitionRows | Where-Object service -eq 'KeyVault').events | Measure-Object -Sum).Sum)",
        'Resource firewall fallback observed: true',
        'Raw service resource IDs published: no',
        'Transition log validation: PASS'
    )
}

$denied = Read-Result 'result-enforced-denied.json'
if ($denied) {
    New-TerminalEvidence -Path (Join-Path $screenshots '07-cli-enforced-dual-403.png') -Title 'Stage 4 — Enforced mode without an access rule' -Tone Deny -Lines @(
        'Association mode: Enforced',
        'NSP access rule present: no',
        "Storage read: HTTP $($denied.storageHttp) — blocked by perimeter",
        "Key Vault read: HTTP $($denied.keyVaultHttp) — blocked by perimeter",
        'Storage RBAC assignment still present: true',
        'Key Vault RBAC assignment still present: true',
        'Expected dual denial: PASS'
    )
}

$allowed = Read-Result 'result-enforced-allowed.json'
$validation = Read-Result 'result-validate.json'
if ($allowed -and $validation -and $logs) {
    $categories = @($logs.rows.category | Sort-Object -Unique)
    New-TerminalEvidence -Path (Join-Path $screenshots '09-cli-recovered-access-logs-zero-drift.png') -Title 'Stages 5–6 — Explicit recovery, logs, and zero drift' -Tone Pass -Lines @(
        'Inbound subscription access rule: enabled',
        "Storage read: HTTP $($allowed.storageHttp)  •  digest match: $([bool]$allowed.storageContentMatch)",
        "Key Vault read: HTTP $($allowed.keyVaultHttp)  •  value match: $([bool]$allowed.keyVaultValueMatch)",
        "Transition fallback category: $('NspPublicInboundResourceRulesAllowed' -in $categories)",
        "Enforced denial category: $('NspPublicInboundPerimeterRulesDenied' -in $categories)",
        "Perimeter allow category: $('NspPublicInboundPerimeterRulesAllowed' -in $categories)",
        "Terraform detailed exit code: $($validation.terraformDetailedExit)",
        'Final validation: PASS'
    )
}

$cleanup = if (Test-Path -LiteralPath (Join-Path $root 'evidence/cleanup-report.json')) {
    Get-Content -Raw -LiteralPath (Join-Path $root 'evidence/cleanup-report.json') | ConvertFrom-Json -Depth 100
}
if ($cleanup) {
    New-TerminalEvidence -Path (Join-Path $screenshots '10-cli-cleanup-baseline-proof.png') -Title 'Stage 7 — Cleanup and protected baseline' -Tone Pass -Lines @(
        "Workshop artifacts remaining: $($cleanup.workshopArtifactsRemaining)",
        "Soft-deleted workshop vaults: $($cleanup.softDeletedWorkshopVaults)",
        "Resources unchanged: $($cleanup.protectedBaseline.resourcesUnchanged)",
        "Role assignments unchanged: $($cleanup.protectedBaseline.roleAssignmentsUnchanged)",
        "Subscription diagnostics unchanged: $($cleanup.protectedBaseline.subscriptionDiagnosticsUnchanged)",
        "Cleanup validation: $($cleanup.validation)",
        'Protected baseline: PASS'
    )
}

$portalRaw = Join-Path $work 'portal-raw'
$learningPortal = Join-Path $portalRaw '02-portal-nsp-learning-associations.raw.png'
if (Test-Path -LiteralPath $learningPortal) {
    Protect-PortalEvidence -Source $learningPortal -Destination (Join-Path $screenshots '02-portal-nsp-learning-associations.png') -Redactions @(
        [System.Drawing.Rectangle]::new(1048, 0, 228, 39),
        [System.Drawing.Rectangle]::new(571, 389, 165, 29),
        [System.Drawing.Rectangle]::new(571, 433, 165, 29),
        [System.Drawing.Rectangle]::new(571, 478, 165, 29)
    ) -Labels @('[account redacted]', '[key-vault]', '[log-workspace]', '[storage-account]')
}

$diagnosticPortal = Join-Path $portalRaw '04-portal-nsp-diagnostic-setting.raw.png'
if (Test-Path -LiteralPath $diagnosticPortal) {
    Protect-PortalEvidence -Source $diagnosticPortal -Destination (Join-Path $screenshots '04-portal-nsp-diagnostic-setting.png') -Redactions @(
        [System.Drawing.Rectangle]::new(1048, 0, 228, 39),
        [System.Drawing.Rectangle]::new(957, 303, 187, 29)
    ) -Labels @('[account redacted]', '[log-workspace]')
}

$enforcedPortal = Join-Path $portalRaw '06-portal-nsp-enforced-associations.raw.png'
if (Test-Path -LiteralPath $enforcedPortal) {
    Protect-PortalEvidence -Source $enforcedPortal -Destination (Join-Path $screenshots '06-portal-nsp-enforced-associations.png') -Redactions @(
        [System.Drawing.Rectangle]::new(1048, 0, 228, 39),
        [System.Drawing.Rectangle]::new(571, 455, 165, 29),
        [System.Drawing.Rectangle]::new(571, 499, 165, 29),
        [System.Drawing.Rectangle]::new(571, 543, 165, 29)
    ) -Labels @('[account redacted]', '[key-vault]', '[log-workspace]', '[storage-account]')
}

$rulePortal = Join-Path $portalRaw '08-portal-nsp-subscription-access-rule.raw.png'
if (Test-Path -LiteralPath $rulePortal) {
    Protect-PortalEvidence -Source $rulePortal -Destination (Join-Path $screenshots '08-portal-nsp-subscription-access-rule.png') -Redactions @(
        [System.Drawing.Rectangle]::new(1048, 0, 228, 39),
        [System.Drawing.Rectangle]::new(1110, 397, 166, 31)
    ) -Labels @('[account redacted]', '[active subscription]')
}

$coverPath = Join-Path $root 'azure-network-security-perimeter-cover.png'
if (Test-Path -LiteralPath $coverPath) {
    $cover = [System.Drawing.Bitmap]::FromFile($coverPath)
    try {
        foreach ($spec in @(
            @{ Width = 1600; Height = 900; Path = (Join-Path $root 'azure-network-security-perimeter-cover-1600x900.png') },
            @{ Width = 444; Height = 251; Path = (Join-Path $root 'azure-network-security-perimeter-tile-444x251.png') }
        )) {
            $bitmap = [System.Drawing.Bitmap]::new($spec.Width, $spec.Height)
            $graphics = [System.Drawing.Graphics]::FromImage($bitmap)
            try {
                $graphics.InterpolationMode = 'HighQualityBicubic'
                $graphics.DrawImage($cover, 0, 0, $spec.Width, $spec.Height)
                Save-Image -Bitmap $bitmap -Path $spec.Path
            }
            finally {
                $graphics.Dispose()
                $bitmap.Dispose()
            }
        }
    }
    finally {
        $cover.Dispose()
    }
}

Write-Host "Rendered available public screenshots to $screenshots"
