param(
  [string]$EvidenceDate = (Get-Date -Format 'yyyy-MM-dd')
)

$ErrorActionPreference = 'Stop'

$projectRoot = (Resolve-Path (Join-Path $PSScriptRoot '..\..')).Path
$frontendRoot = Join-Path $projectRoot 'frontend\admin'
$evidenceRoot = Join-Path $projectRoot "docs\evidence\ops\$EvidenceDate\sca"
$goCacheRoot = Join-Path $projectRoot '.cache'
$goBuildCache = Join-Path $goCacheRoot 'go-build'
$goModCache = Join-Path $goCacheRoot 'gomod'
$goPath = Join-Path $goCacheRoot 'gopath'

New-Item -ItemType Directory -Force $evidenceRoot, $goBuildCache, $goModCache, $goPath | Out-Null

function Invoke-CapturedCommand {
  param(
    [Parameter(Mandatory = $true)][string]$FilePath,
    [string[]]$ArgumentList = @(),
    [Parameter(Mandatory = $true)][string]$WorkingDirectory,
    [Parameter(Mandatory = $true)][string]$StdOutPath,
    [Parameter(Mandatory = $true)][string]$StdErrPath
  )

  Remove-Item $StdOutPath, $StdErrPath -Force -ErrorAction SilentlyContinue
  $process = Start-Process `
    -FilePath $FilePath `
    -ArgumentList $ArgumentList `
    -WorkingDirectory $WorkingDirectory `
    -PassThru `
    -WindowStyle Hidden `
    -RedirectStandardOutput $StdOutPath `
    -RedirectStandardError $StdErrPath `
    -Wait

  return $process.ExitCode
}

function Get-NpmAuditCounts {
  param(
    [Parameter(Mandatory = $true)][string]$JsonPath
  )

  if (-not (Test-Path $JsonPath)) {
    return $null
  }

  $raw = Get-Content $JsonPath -Raw
  if ([string]::IsNullOrWhiteSpace($raw)) {
    return $null
  }

  $payload = $raw | ConvertFrom-Json
  if (-not $payload.metadata -or -not $payload.metadata.vulnerabilities) {
    return $null
  }

  return $payload.metadata.vulnerabilities
}

function Get-GovulnFindingCount {
  param(
    [Parameter(Mandatory = $true)][string]$JsonPath
  )

  if (-not (Test-Path $JsonPath)) {
    return [pscustomobject]@{
      Count = 0
      IDs = @()
    }
  }

  $count = 0
  $ids = New-Object System.Collections.Generic.HashSet[string]
  $insideFinding = $false
  foreach ($line in Get-Content $JsonPath) {
    if ($line -match '"finding"') {
      $insideFinding = $true
      $count++
      continue
    }
    if ($insideFinding -and $line -match '"osv":\s*"([^"]+)"') {
      [void]$ids.Add($Matches[1])
      $insideFinding = $false
    }
  }

  return [pscustomobject]@{
    Count = $count
    IDs = @($ids)
  }
}

$timestamp = Get-Date -Format 'yyyyMMdd-HHmmss'
$prodAuditJson = Join-Path $evidenceRoot "npm-audit-prod-$timestamp.json"
$prodAuditErr = Join-Path $evidenceRoot "npm-audit-prod-$timestamp.stderr.txt"
$fullAuditJson = Join-Path $evidenceRoot "npm-audit-full-$timestamp.json"
$fullAuditErr = Join-Path $evidenceRoot "npm-audit-full-$timestamp.stderr.txt"
$govulnJson = Join-Path $evidenceRoot "govulncheck-$timestamp.jsonl"
$govulnErr = Join-Path $evidenceRoot "govulncheck-$timestamp.stderr.txt"
$summaryPath = Join-Path $evidenceRoot "SCA_SUMMARY_$timestamp.md"

$prodAuditExit = Invoke-CapturedCommand `
  -FilePath 'npm.cmd' `
  -ArgumentList @('audit', '--omit=dev', '--json', '--registry=https://registry.npmjs.org/') `
  -WorkingDirectory $frontendRoot `
  -StdOutPath $prodAuditJson `
  -StdErrPath $prodAuditErr

$fullAuditExit = Invoke-CapturedCommand `
  -FilePath 'npm.cmd' `
  -ArgumentList @('audit', '--json', '--registry=https://registry.npmjs.org/') `
  -WorkingDirectory $frontendRoot `
  -StdOutPath $fullAuditJson `
  -StdErrPath $fullAuditErr

Push-Location $projectRoot
try {
  $env:GOCACHE = $goBuildCache
  $env:GOMODCACHE = $goModCache
  $env:GOPATH = $goPath
  $govulnExit = Invoke-CapturedCommand `
    -FilePath 'go' `
    -ArgumentList @('run', 'golang.org/x/vuln/cmd/govulncheck@latest', '-json', './...') `
    -WorkingDirectory $projectRoot `
    -StdOutPath $govulnJson `
    -StdErrPath $govulnErr
} finally {
  Pop-Location
  Remove-Item Env:GOCACHE, Env:GOMODCACHE, Env:GOPATH -ErrorAction SilentlyContinue
}

$prodCounts = Get-NpmAuditCounts -JsonPath $prodAuditJson
$fullCounts = Get-NpmAuditCounts -JsonPath $fullAuditJson
$govulnFindings = Get-GovulnFindingCount -JsonPath $govulnJson
$prodFindingSummary = if ($prodCounts) {
  "info=$($prodCounts.info) low=$($prodCounts.low) moderate=$($prodCounts.moderate) high=$($prodCounts.high) critical=$($prodCounts.critical) total=$($prodCounts.total)"
} else {
  'unavailable'
}
$fullFindingSummary = if ($fullCounts) {
  "info=$($fullCounts.info) low=$($fullCounts.low) moderate=$($fullCounts.moderate) high=$($fullCounts.high) critical=$($fullCounts.critical) total=$($fullCounts.total)"
} else {
  'unavailable'
}
$govulnIDsSummary = if ($govulnFindings.IDs.Count -gt 0) {
  ($govulnFindings.IDs | Sort-Object) -join ', '
} else {
  'none'
}
$prodAuditJsonName = Split-Path $prodAuditJson -Leaf
$prodAuditErrName = Split-Path $prodAuditErr -Leaf
$fullAuditJsonName = Split-Path $fullAuditJson -Leaf
$fullAuditErrName = Split-Path $fullAuditErr -Leaf
$govulnJsonName = Split-Path $govulnJson -Leaf
$govulnErrName = Split-Path $govulnErr -Leaf

$summaryLines = @(
  '# SCA Summary',
  '',
  "- Generated at: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss zzz')",
  "- Project root: $projectRoot",
  '',
  '## Commands',
  '',
  '- `cd frontend/admin && npm.cmd audit --omit=dev --json --registry=https://registry.npmjs.org/`',
  '- `cd frontend/admin && npm.cmd audit --json --registry=https://registry.npmjs.org/`',
  '- `go run golang.org/x/vuln/cmd/govulncheck@latest -json ./...`',
  '',
  '## Exit Codes',
  '',
  "- npm audit production: $prodAuditExit",
  "- npm audit full: $fullAuditExit",
  "- govulncheck: $govulnExit",
  '',
  '## Findings',
  '',
  "- npm audit production: $prodFindingSummary",
  "- npm audit full: $fullFindingSummary",
  "- govulncheck reachable findings: $($govulnFindings.Count)",
  "- govulncheck reachable IDs: $govulnIDsSummary",
  '',
  '## Evidence Files',
  '',
  "- $prodAuditJsonName",
  "- $prodAuditErrName",
  "- $fullAuditJsonName",
  "- $fullAuditErrName",
  "- $govulnJsonName",
  "- $govulnErrName",
  ''
)

Set-Content -Path $summaryPath -Value ($summaryLines -join [Environment]::NewLine) -Encoding UTF8
Get-Content $summaryPath
