#requires -Version 7.2
[CmdletBinding()]
param(
    [string]$DestinationPath
)

Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
$root = Split-Path -Parent $PSScriptRoot
if (-not $DestinationPath) {
    $DestinationPath = Join-Path $root 'azure-machine-configuration-deep-dive-source.zip'
}

$stage = Join-Path $root '.bundle-staging'
$resolvedRoot = [IO.Path]::GetFullPath($root).TrimEnd('\')
$resolvedStage = [IO.Path]::GetFullPath($stage).TrimEnd('\')
if (-not $resolvedStage.StartsWith("$resolvedRoot\", [StringComparison]::OrdinalIgnoreCase)) {
    throw 'The bundle staging path is outside the workshop root.'
}

if (Test-Path -LiteralPath $stage) {
    Remove-Item -LiteralPath $stage -Recurse -Force
}
New-Item -ItemType Directory -Path $stage | Out-Null

try {
    foreach ($file in @('README.md', 'workshop.md', 'publishing-brief.md', 'validation-transcript.md', 'sanitized-evidence.md', '.gitignore')) {
        Copy-Item -LiteralPath (Join-Path $root $file) -Destination (Join-Path $stage $file)
    }

    foreach ($directory in @('assets', 'packages', 'screenshots', 'scripts')) {
        Copy-Item -LiteralPath (Join-Path $root $directory) -Destination (Join-Path $stage $directory) -Recurse
    }

    $sanitizedPolicyRoot = Join-Path $stage 'policies'
    New-Item -ItemType Directory -Path $sanitizedPolicyRoot | Out-Null
    $context = Get-Content -Raw -LiteralPath (Join-Path $root '.private\runtime-context.json') | ConvertFrom-Json
    Get-ChildItem -LiteralPath (Join-Path $root 'policies\generated') -Recurse -Filter '*.json' | ForEach-Object {
        $relative = $_.FullName.Substring((Join-Path $root 'policies\generated').Length).TrimStart('\')
        $target = Join-Path $sanitizedPolicyRoot $relative
        New-Item -ItemType Directory -Path (Split-Path -Parent $target) -Force | Out-Null
        $text = Get-Content -Raw -LiteralPath $_.FullName
        $text = $text.Replace([string]$context.SubscriptionId, '<subscription-id>')
        $text = $text.Replace([string]$context.StorageAccountName, '<storage-account-name>')
        $text = $text.Replace([string]$context.ManagedIdentityResourceId, '<package-identity-resource-id>')
        $text = [regex]::Replace($text, '(?i)/subscriptions/[0-9a-f-]{36}', '/subscriptions/<subscription-id>')
        Set-Content -LiteralPath $target -Value $text -Encoding utf8
    }

    $forbidden = [ordered]@{
        Email             = '(?i)\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b'
        BearerToken       = '(?i)Bearer\s+[A-Za-z0-9._~-]{20,}'
        SharedAccessKey   = '(?i)(?:AccountKey|SharedAccessSignature)\s*[:=]\s*["'']?[A-Za-z0-9+/=_-]{20,}|[?&]sig=[A-Za-z0-9%+/=_-]{20,}'
    }
    $enforceIdentityValue = if ($context.PSObject.Properties.Name -contains 'EnforceAssignmentPrincipalId') { $context.EnforceAssignmentPrincipalId } else { $null }
    $sensitiveValues = @(
        $context.SubscriptionId,
        $context.AuthorObjectId,
        $context.ManagedIdentityPrincipalId,
        $enforceIdentityValue,
        $context.StorageAccountName
    ) | Where-Object { $_ } | Select-Object -Unique

    $textFiles = Get-ChildItem -LiteralPath $stage -Recurse -File | Where-Object Extension -in @('.md', '.ps1', '.json', '.txt')
    $violations = foreach ($file in $textFiles) {
        $content = Get-Content -Raw -LiteralPath $file.FullName
        foreach ($rule in $forbidden.GetEnumerator()) {
            if ($content -match $rule.Value) {
                [pscustomobject]@{ File = $file.FullName.Substring($stage.Length + 1); Rule = $rule.Key }
            }
        }
        foreach ($sensitiveValue in $sensitiveValues) {
            if ($content.Contains([string]$sensitiveValue, [StringComparison]::OrdinalIgnoreCase)) {
                [pscustomobject]@{ File = $file.FullName.Substring($stage.Length + 1); Rule = 'LiveIdentifier' }
            }
        }
    }
    if ($violations) {
        throw "Bundle safety scan failed:`n$($violations | Format-Table -AutoSize | Out-String)"
    }

    if (Test-Path -LiteralPath $DestinationPath) {
        Remove-Item -LiteralPath $DestinationPath -Force
    }
    Compress-Archive -Path (Join-Path $stage '*') -DestinationPath $DestinationPath -CompressionLevel Optimal
    $zip = Get-Item -LiteralPath $DestinationPath
    [pscustomobject]@{
        Path       = $zip.FullName
        SizeMB     = [math]::Round($zip.Length / 1MB, 2)
        FileCount  = @(Get-ChildItem -LiteralPath $stage -Recurse -File).Count
        SafetyScan = 'Passed'
    }
}
finally {
    if (Test-Path -LiteralPath $stage) {
        Remove-Item -LiteralPath $stage -Recurse -Force
    }
}
