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 Get-FormalTasks {
  param([string]$TaskPath)

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

  try {
    $taskDocument = Get-Content -LiteralPath $TaskPath -Raw | ConvertFrom-Json
  }
  catch {
    return @()
  }

  $tasks = @($taskDocument.tasks)
  return @($tasks | Where-Object {
      @("feature_research", "feature_spec", "feature_design", "feature_plan", "testcase_design", "feature_impl", "release", "archive") -contains [string]$_.task_kind
    })
}

function Get-RealDevPlans {
  param([string]$PlansRoot)

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

  return @(
    Get-ChildItem -Path $PlansRoot -Recurse -Filter "*.dev-plan.md" -File -ErrorAction SilentlyContinue |
      Where-Object { $_.Name -ne "_template.dev-plan.md" }
  )
}

$issues = @()
$taskPath = Join-Path $ProjectRoot "task.json"
$formalTasks = @(Get-FormalTasks -TaskPath $taskPath)

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

  Write-Output "Business goal lint skipped: no formal task queue."
  exit 0
}

$prdPath = Join-Path $ProjectRoot "docs\product\prd-lite.md"
$featurePackPath = Join-Path $ProjectRoot "docs\context\feature-pack.md"
$plansRoot = Join-Path $ProjectRoot "plans"

$prd = Get-FileContentOrNull -Path $prdPath
if ($null -eq $prd) {
  $issues += New-Issue -Severity "error" -File "docs/product/prd-lite.md" -Section "file" -Message "缺少 PRD-Lite，无法为正式任务提供业务背景、问题、目标、受益对象和成功标准。"
}
elseif (-not (Test-ContainsAll -Content $prd -Terms @("## 2. 背景与问题", "为什么现在做:", "不做的影响:", "## 4. 用户与角色", "## 15. 成功标准"))) {
  $issues += New-Issue -Severity "error" -File "docs/product/prd-lite.md" -Section "business-goal" -Message "PRD-Lite 缺少业务目标层必需段落：为什么现在做、不做影响、用户与角色或成功标准。"
}

$featurePack = Get-FileContentOrNull -Path $featurePackPath
if ($null -eq $featurePack) {
  $issues += New-Issue -Severity "error" -File "docs/context/feature-pack.md" -Section "file" -Message "缺少 feature-pack，无法把业务目标收敛到实现上下文。"
}
elseif (-not (Test-ContainsAll -Content $featurePack -Terms @("## 2. 业务目标", "解决什么问题", "成功后的业务结果", "本期不解决什么问题"))) {
  $issues += New-Issue -Severity "error" -File "docs/context/feature-pack.md" -Section "business-goal" -Message "feature-pack 缺少问题、业务结果或非目标描述。"
}

$devPlans = @(Get-RealDevPlans -PlansRoot $plansRoot)
if ($devPlans.Count -eq 0) {
  $issues += New-Issue -Severity "error" -File "plans/**/*.dev-plan.md" -Section "file" -Message "缺少真实 dev-plan；仅安装 `_template.dev-plan.md` 不算完成计划真相源。"
}
else {
  $devPlanContent = Get-FileContentOrNull -Path $devPlans[0].FullName
  if ($null -eq $devPlanContent -or -not (Test-ContainsAll -Content $devPlanContent -Terms @("## 2. 目标与完成定义", "业务目标:"))) {
    $relativePlanPath = $devPlans[0].FullName.Substring($ProjectRoot.Length).TrimStart('\', '/')
    $issues += New-Issue -Severity "error" -File $relativePlanPath -Section "business-goal" -Message "dev-plan 缺少“目标与完成定义 / 业务目标”段落。"
  }
}

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

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

exit $exitCode
