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 Test-ContainsAll {
  param(
    [string]$Content,
    [string[]]$Terms
  )

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

  return $true
}

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

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

  return $null
}

$issues = @()

$domainModelPath = Resolve-FirstExistingPath -Candidates @(
  (Join-Path $ProjectRoot "docs\context\domain-model.md"),
  (Join-Path $ProjectRoot "docs\ai\domain-model.md"),
  (Join-Path $ProjectRoot "docs\codex-harness-engineering\templates\context\domain-model.md")
)
$repoMapPath = Resolve-FirstExistingPath -Candidates @(
  (Join-Path $ProjectRoot "docs\ai\repo-map.md"),
  (Join-Path $ProjectRoot "docs\codex-harness-engineering\templates\context\repo-map.md")
)
$architectureBriefPath = Resolve-FirstExistingPath -Candidates @(
  (Join-Path $ProjectRoot "docs\ai\architecture-brief.md"),
  (Join-Path $ProjectRoot "docs\codex-harness-engineering\templates\context\architecture-brief.md")
)
$featureTemplatePath = 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"
$stage2PromptPath = Join-Path $ProjectRoot ".codex\prompts\review-stage2-quality.md"

$domainModel = Get-FileContentOrNull -Path $domainModelPath
if ($null -eq $domainModel) {
  $issues += New-Issue -Severity "error" -File "docs/context/domain-model.md" -Section "file" -Message "缺少领域模型模板或已安装领域模型文档。"
}
elseif (-not (Test-ContainsAll -Content $domainModel -Terms @("## 2. 核心实体", "## 4. 状态模型", "## 5. 业务规则", "## 6. 不变量", "## 7. 领域逻辑落点"))) {
  $issues += New-Issue -Severity "error" -File "docs/context/domain-model.md" -Section "structure" -Message "领域模型模板缺少核心实体、状态模型、业务规则、不变量或逻辑落点章节。"
}

$repoMap = Get-FileContentOrNull -Path $repoMapPath
if ($null -eq $repoMap -or -not (Test-ContainsAll -Content $repoMap -Terms @("领域入口", "核心实体", "状态流转", "业务规则", "不变量"))) {
  $issues += New-Issue -Severity "error" -File "docs/ai/repo-map.md" -Section "domain-entry" -Message "repo-map 缺少领域模型入口。"
}

$architectureBrief = Get-FileContentOrNull -Path $architectureBriefPath
if ($null -eq $architectureBrief -or -not (Test-ContainsAll -Content $architectureBrief -Terms @("领域模型入口", "核心实体入口", "状态流转入口", "业务规则入口", "不变量入口"))) {
  $issues += New-Issue -Severity "error" -File "docs/ai/architecture-brief.md" -Section "domain-entry" -Message "architecture-brief 缺少领域模型入口。"
}

$featureTemplate = Get-FileContentOrNull -Path $featureTemplatePath
if ($null -eq $featureTemplate -or -not (Test-ContainsAll -Content $featureTemplate -Terms @('"domain_entities"', '"state_model"', '"business_rules"', '"invariants"', '"domain_logic_locations"', '"domain_model_summary"'))) {
  $issues += New-Issue -Severity "error" -File "tools/harness/templates/feature-task-reference.json" -Section "task-fields" -Message "feature-task-reference 缺少领域模型 task 字段。"
}

$implementPrompt = Get-FileContentOrNull -Path $implementPromptPath
if ($null -eq $implementPrompt -or -not (Test-ContainsAll -Content $implementPrompt -Terms @("Codebase Recon", "核心实体", "状态流转", "业务规则", "不变量", "现有实现位置"))) {
  $issues += New-Issue -Severity "error" -File ".codex/prompts/implement-one-task.md" -Section "recon" -Message "implement prompt 缺少领域模型 Recon 约束。"
}

$stage1Prompt = Get-FileContentOrNull -Path $stage1PromptPath
if ($null -eq $stage1Prompt -or -not (Test-ContainsAll -Content $stage1Prompt -Terms @("核心实体", "状态流转", "业务规则", "不变量", "domain_rule_gap"))) {
  $issues += New-Issue -Severity "error" -File ".codex/prompts/review-stage1-spec.md" -Section "domain-review" -Message "Stage 1 prompt 缺少领域规则检查。"
}

$stage2Prompt = Get-FileContentOrNull -Path $stage2PromptPath
if ($null -eq $stage2Prompt -or -not (Test-ContainsAll -Content $stage2Prompt -Terms @("复制、分散或重复实现了同一领域规则", "状态机", "不变量", '必须 `FAIL`'))) {
  $issues += New-Issue -Severity "error" -File ".codex/prompts/review-stage2-quality.md" -Section "domain-review" -Message "Stage 2 prompt 缺少领域逻辑复制/分散检查。"
}

$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 "Domain model lint passed."
  exit 0
}

if ($errors.Count -gt 0) {
  Write-Output "Domain model 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 "Domain model lint passed with warnings."
  }
  foreach ($issue in $warnings) {
    Write-Output ("- [WARNING] {0} :: {1} :: {2}" -f $issue.file, $issue.section, $issue.message)
  }
}

exit $exitCode
