$ErrorActionPreference = 'Stop'
$root = Split-Path -Parent $MyInvocation.MyCommand.Path
$campaignId = 'AIBLACK-300-20260830T183052882Z'
$expectedPack = @(
  'AUDIT_REPRISE_V1.md','BARAME_300_V1.md','CERTIFICAT_COHERENCE_V1.md',
  'JOURNAL_APPEND_ONLY_V1.ndjson','MANIFEST_V1.json','README_LANCEMENT_V1.md',
  'SEAL_PRE_Q001_V1.md','SHA256_FILES_V1.json','TEST_BLANC_NEUTRE_V1.json',
  'VERIFY_V1.ps1','questions_level_5A.tsv','questions_level_5B.tsv','questions_level_5C.tsv'
)
foreach ($name in $expectedPack) {
  if (-not (Test-Path -LiteralPath (Join-Path $root $name) -PathType Leaf)) { throw "MISSING:$name" }
}
$allIds = New-Object System.Collections.Generic.List[string]
$totalPoints = 0
foreach ($spec in @(@('5A',1,100),@('5B',101,200),@('5C',201,300))) {
  $level=$spec[0]; $first=[int]$spec[1]; $last=[int]$spec[2]
  $path=Join-Path $root "questions_level_$level.tsv"
  $lines=@(Get-Content -LiteralPath $path)
  if ($lines.Count -ne 100) { throw "COUNT:$level" }
  for ($n=$first; $n -le $last; $n++) {
    $index=$n-$first; $f=$lines[$index].Split("`t")
    if ($f.Count -ne 7) { throw "TSV:${level}:$n" }
    $id='Q{0:D3}' -f $n
    if ($f[0] -ne $id -or $f[1] -ne $level -or $f[2] -ne '4') { throw "ROW:$id" }
    if ([string]::IsNullOrWhiteSpace($f[3]) -or [string]::IsNullOrWhiteSpace($f[5]) -or [string]::IsNullOrWhiteSpace($f[6])) { throw "EMPTY:$id" }
    $allIds.Add($id); $totalPoints += 4
  }
}
if (($allIds | Sort-Object -Unique).Count -ne 300 -or $totalPoints -ne 1200) { throw 'TOTALS' }
$barame=Get-Content -Raw -LiteralPath (Join-Path $root 'BARAME_300_V1.md')
if (([regex]::Matches($barame,'(?m)^Q\d{3} — Niveau ')).Count -ne 300) { throw 'BARAME_COUNT' }
if (-not $barame.Contains($campaignId)) { throw 'BARAME_ID' }
$manifest=Get-Content -Raw -LiteralPath (Join-Path $root 'MANIFEST_V1.json') | ConvertFrom-Json
if ($manifest.campaign_id -ne $campaignId -or $manifest.questions.total -ne 300 -or $manifest.questions.total_points -ne 1200) { throw 'MANIFEST' }
if ($manifest.excluded_from_pack -notcontains 'AUDIT_ORIGINALS' -or $manifest.pack_files -contains 'AUDIT_ORIGINALS') { throw 'QUARANTINE' }
if (@($manifest.pack_files).Count -ne $expectedPack.Count -or @($expectedPack | Where-Object { $manifest.pack_files -notcontains $_ }).Count -ne 0) { throw 'PACK_SET' }
$tb=Get-Content -Raw -LiteralPath (Join-Path $root 'TEST_BLANC_NEUTRE_V1.json') | ConvertFrom-Json
if ($tb.executed -ne $false -or $tb.status -ne 'PREPARED_NOT_EXECUTED' -or @($tb.tests).Count -ne 2) { throw 'TEST_BLANK' }
foreach ($t in $tb.tests) {
  if ($t.distinct_from_exam -ne $true -or $t.request.mode -ne 'black' -or $t.request.power -ne 3 -or @($t.request.messages).Count -ne 1 -or $t.request.messages[0].role -ne 'user') { throw "TEST_SCHEMA:$($t.id)" }
}
$prev='GENESIS'; $seq=0
foreach ($line in Get-Content -LiteralPath (Join-Path $root 'JOURNAL_APPEND_ONLY_V1.ndjson')) {
  $e=$line | ConvertFrom-Json; $seq++
  if ($e.seq -ne $seq -or $e.prev_hash -ne $prev -or $e.campaign_id -ne $campaignId) { throw "JOURNAL_LINK:$seq" }
  $timestampCanonical=([DateTime]$e.timestamp_utc).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss.fffZ')
  $canonical="$($e.seq)|$timestampCanonical|$($e.campaign_id)|$($e.event)|$($e.prev_hash)"
  $bytes=[Text.Encoding]::UTF8.GetBytes($canonical)
  $calc=[Convert]::ToHexString([Security.Cryptography.SHA256]::HashData($bytes)).ToLowerInvariant()
  if ($e.entry_hash -ne $calc) { throw "JOURNAL_HASH:$seq" }; $prev=$calc
}
if ($seq -lt 4) { throw 'JOURNAL_COUNT' }
$inventory=Get-Content -Raw -LiteralPath (Join-Path $root 'SHA256_FILES_V1.json') | ConvertFrom-Json
if ($inventory.algorithm -ne 'SHA-256' -or $inventory.self_excluded -ne 'SHA256_FILES_V1.json') { throw 'HASH_POLICY' }
$hashExpected=@($expectedPack | Where-Object { $_ -ne 'SHA256_FILES_V1.json' } | Sort-Object)
$hashListed=@($inventory.files.name | Sort-Object)
if (@(Compare-Object $hashExpected $hashListed).Count -ne 0) { throw 'HASH_SET' }
foreach ($item in $inventory.files) {
  $actual=(Get-FileHash -LiteralPath (Join-Path $root $item.name) -Algorithm SHA256).Hash.ToLowerInvariant()
  if ($actual -ne $item.sha256) { throw "HASH:$($item.name)" }
}
Write-Output 'VERIFY_OK'
