param(
  [string]$ProjectRoot = "",
  [switch]$AsJson
)

Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"

if ([string]::IsNullOrWhiteSpace($ProjectRoot)) {
  $ProjectRoot = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot "..\..\..\.."))
}

function New-Issue {
  param(
    [string]$Severity,
    [string]$File,
    [string]$Section,
    [string]$Message
  )

  [PSCustomObject]@{
    severity = $Severity
    file = $File
    section = $Section
    message = $Message
  }
}

function Get-FileContentOrNull {
  param([string]$Path)

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

  Get-Content -LiteralPath $Path -Raw
}

function Resolve-FirstExistingPath {
  param([string[]]$Candidates)

  foreach ($candidate in $Candidates) {
    if (Test-Path -LiteralPath $candidate) {
      return $candidate
    }
  }

  return $null
}

function Test-ContainsAll {
  param(
    [string]$Content,
    [string[]]$Terms
  )

  foreach ($term in $Terms) {
    if ($Content -notmatch [regex]::Escape($term)) {
      return $false
    }
  }

  return $true
}

$issues = @()

$installManifestPath = Resolve-FirstExistingPath -Candidates @(
  (Join-Path $ProjectRoot "install-manifest.json"),
  (Join-Path $ProjectRoot "cli\package-source\install-manifest.json")
)
$projectTaskTemplatePath = Join-Path $ProjectRoot "tools\harness\templates\project-task-template.json"
$featureTaskTemplatePath = Join-Path $ProjectRoot "tools\harness\templates\feature-task-reference.json"
$implementPromptPath = Join-Path $ProjectRoot ".codex\prompts\implement-one-task.md"
$stage1PromptPath = Join-Path $ProjectRoot ".codex\prompts\review-stage1-spec.md"
$codexLoopPath = Join-Path $ProjectRoot "tools\harness\codex-loop.ps1"
$traceSchemaPath = Resolve-FirstExistingPath -Candidates @(
  (Join-Path $ProjectRoot "docs\harness\trace.schema.json"),
  (Join-Path $ProjectRoot "docs\codex-harness-engineering\templates\trace\trace.schema.json")
)
$bootstrapPath = Join-Path $ProjectRoot "tools\install\bootstrap-codex-harness.ps1"
$verifyPath = Join-Path $ProjectRoot "tools\harness\verify.ps1"
$installSmokePath = Join-Path $ProjectRoot "tools\harness\tests\test-install-modes.ps1"
$layoutSmokePath = Join-Path $ProjectRoot "tools\harness\tests\test-project-root-layout.ps1"

$installManifest = Get-FileContentOrNull -Path $installManifestPath
if ($null -eq $installManifest) {
  $issues += New-Issue -Severity "error" -File "install-manifest.json" -Section "file" -Message "缺少 install-manifest，无法证明 truth source 安装面。"
}
elseif (-not (Test-ContainsAll -Content $installManifest -Terms @('"templates/runtime/AGENTS.md"', '"AGENTS.md"', '"templates/context/repo-map.md"', '"docs/ai/repo-map.md"', '"templates/context/architecture-brief.md"', '"docs/ai/architecture-brief.md"', '"templates/testing/"', '"docs/testing/"', '"templates/knowledge/"', '"docs/knowledge/"', '"templates/tools/harness/truth-source-lint.ps1"', '"tools/harness/truth-source-lint.ps1"'))) {
  $issues += New-Issue -Severity "error" -File "install-manifest.json" -Section "install-surface" -Message "install-manifest 没有完整覆盖 AGENTS、repo-map、architecture-brief、testing、knowledge 或 truth-source-lint。"
}

$projectTaskTemplate = Get-FileContentOrNull -Path $projectTaskTemplatePath
if ($null -eq $projectTaskTemplate -or -not (Test-ContainsAll -Content $projectTaskTemplate -Terms @('"context_files"', '"required_truth_sources"'))) {
  $issues += New-Issue -Severity "error" -File "tools/harness/templates/project-task-template.json" -Section "task-template" -Message "project-task-template 缺少 context_files 或 required_truth_sources。"
}

$featureTaskTemplate = Get-FileContentOrNull -Path $featureTaskTemplatePath
if ($null -eq $featureTaskTemplate -or -not (Test-ContainsAll -Content $featureTaskTemplate -Terms @('"context_files"', '"required_truth_sources"'))) {
  $issues += New-Issue -Severity "error" -File "tools/harness/templates/feature-task-reference.json" -Section "task-template" -Message "feature-task-reference 缺少 context_files 或 required_truth_sources。"
}

$implementPrompt = Get-FileContentOrNull -Path $implementPromptPath
if ($null -eq $implementPrompt) {
  $issues += New-Issue -Severity "error" -File ".codex/prompts/implement-one-task.md" -Section "file" -Message "缺少 implement prompt。"
}
elseif (-not (Test-ContainsAll -Content $implementPrompt -Terms @("required_truth_sources", "输出 BLOCKED", "Truth Sources Used", "Context Files Used"))) {
  $issues += New-Issue -Severity "error" -File ".codex/prompts/implement-one-task.md" -Section "prompt" -Message "implement prompt 没有把 required truth source、BLOCKED、Truth Sources Used 或 Context Files Used 做成执行链要求。"
}

$stage1Prompt = Get-FileContentOrNull -Path $stage1PromptPath
if ($null -eq $stage1Prompt) {
  $issues += New-Issue -Severity "error" -File ".codex/prompts/review-stage1-spec.md" -Section "file" -Message "缺少 Stage 1 review prompt。"
}
elseif (-not (Test-ContainsAll -Content $stage1Prompt -Terms @("Truth source completeness", "truth_source_missing", "Truth Sources Used"))) {
  $issues += New-Issue -Severity "error" -File ".codex/prompts/review-stage1-spec.md" -Section "prompt" -Message "Stage 1 prompt 缺少 truth source completeness、truth_source_missing 或 Truth Sources Used 检查。"
}

$codexLoop = Get-FileContentOrNull -Path $codexLoopPath
if ($null -eq $codexLoop) {
  $issues += New-Issue -Severity "error" -File "tools/harness/codex-loop.ps1" -Section "file" -Message "缺少 codex-loop runtime。"
}
elseif (-not (Test-ContainsAll -Content $codexLoop -Terms @("truth_source_state", "truth_sources_used", "context_files_used", "truth_source_gaps", "package_root_fallbacks"))) {
  $issues += New-Issue -Severity "error" -File "tools/harness/codex-loop.ps1" -Section "runtime" -Message "codex-loop 未记录 truth source 使用证据或 packageRoot fallback。"
}

$traceSchema = Get-FileContentOrNull -Path $traceSchemaPath
if ($null -eq $traceSchema) {
  $issues += New-Issue -Severity "error" -File "docs/harness/trace.schema.json" -Section "file" -Message "缺少 trace schema。"
}
elseif (-not (Test-ContainsAll -Content $traceSchema -Terms @('"truth_sources_used"', '"context_files_used"', '"truth_source_gaps"', '"package_root_fallbacks"'))) {
  $issues += New-Issue -Severity "error" -File "docs/harness/trace.schema.json" -Section "trace" -Message "trace schema 缺少 truth source 实际使用与缺口字段。"
}

$bootstrap = Get-FileContentOrNull -Path $bootstrapPath
if ($null -eq $bootstrap -or -not (Test-ContainsAll -Content $bootstrap -Terms @('tools\harness\truth-source-lint.ps1', 'docs\ai\repo-map.md', 'docs\ai\architecture-brief.md', 'knowledge-catalog.md'))) {
  $issues += New-Issue -Severity "error" -File "tools/install/bootstrap-codex-harness.ps1" -Section "install" -Message "bootstrap 没有安装 truth-source-lint 或 truth source 关键目标文件。"
}

$verify = Get-FileContentOrNull -Path $verifyPath
if ($null -eq $verify -or -not (Test-ContainsAll -Content $verify -Terms @('truth-source-lint.ps1', 'Invoke-TruthSourceValidation'))) {
  $issues += New-Issue -Severity "error" -File "tools/harness/verify.ps1" -Section "verify" -Message "verify 没有接入 truth-source-lint。"
}

$installSmoke = Get-FileContentOrNull -Path $installSmokePath
if ($null -eq $installSmoke -or -not (Test-ContainsAll -Content $installSmoke -Terms @('docs\ai\repo-map.md', 'docs\ai\architecture-brief.md', 'docs\knowledge\knowledge-catalog.md', 'tools\harness\truth-source-lint.ps1'))) {
  $issues += New-Issue -Severity "error" -File "tools/harness/tests/test-install-modes.ps1" -Section "smoke" -Message "安装 smoke 没有覆盖 repo-map、architecture-brief、knowledge-catalog 或 truth-source-lint。"
}

$layoutSmoke = Get-FileContentOrNull -Path $layoutSmokePath
if ($null -eq $layoutSmoke -or -not (Test-ContainsAll -Content $layoutSmoke -Terms @('"AGENTS.md"'))) {
  $issues += New-Issue -Severity "error" -File "tools/harness/tests/test-project-root-layout.ps1" -Section "layout" -Message "project root layout smoke 没有覆盖 AGENTS.md。"
}

$errors = @($issues | Where-Object { $_.severity -eq "error" })
$warnings = @($issues | Where-Object { $_.severity -eq "warning" })
$exitCode = if ($errors.Count -gt 0) { 1 } elseif ($warnings.Count -gt 0) { 2 } else { 0 }

if ($AsJson) {
  [PSCustomObject]@{
    ok = ($exitCode -eq 0)
    errors = $errors
    warnings = $warnings
  } | ConvertTo-Json -Depth 6
  exit $exitCode
}

if ($errors.Count -eq 0 -and $warnings.Count -eq 0) {
  Write-Output "Truth source lint passed."
  exit 0
}

if ($errors.Count -gt 0) {
  Write-Output "Truth source lint failed."
  foreach ($issue in $errors) {
    Write-Output ("- [ERROR] {0} :: {1} :: {2}" -f $issue.file, $issue.section, $issue.message)
  }
}

if ($warnings.Count -gt 0) {
  if ($errors.Count -eq 0) {
    Write-Output "Truth source lint passed with warnings."
  }
  foreach ($issue in $warnings) {
    Write-Output ("- [WARNING] {0} :: {1} :: {2}" -f $issue.file, $issue.section, $issue.message)
  }
}

exit $exitCode
