# naming-scan.ps1 - MAY SOI TEN, tang BO MAY (SOLUTION_ERP)
#
# Chuan thi hanh: docs/governance/naming-standard.md (ky S180 / 2026-08-07, wave W1).
# Kiem ke may doc ten: runs/2026-08-07-S180-adap-upgrade-pack-phased/sub-w1a-mayd-octen.md
#
# HOP DONG CUA MAY NAY - doc truoc khi sua:
#
#  (1) INFORM-only. LUON exit 0, ke ca khi co co. Lai ma thoat = wave W3b,
#      sau khi chu du an chot cau P1 (da chot PA-2). Ly do do duoc (lane F):
#      bat gate ma chua soak => 8-12 lop no ton keu cung luc, nguoi tuong may
#      hong roi tat may.
#
#  (2) Quet 231 TEN VAT-BO-MAY, KHONG quet 1.545 tep .md.
#      Ly do: 5 vung dong bang = 1.131/1.545 = 73,2% kho, va 225/248 cho lech
#      (90,7%) nam TRONG vung mien tru => may quet .md se in "0 hit" ngay dau
#      va so 0 do VO NGHIA (bay-4 cua san GD-1).
#      Tap 231 co 0 mien tru vung, va 23 vat lech that van nam nguyen trong do.
#
#  (3) LUON IN MAU SO canh moi con so. Phien S180 da 7 ca bay don-vi.
#
#  (4) CAM 3 LOI CAM (R6 - lane a dat ten, ca 3 deu co that trong kho nay):
#      (a) liet-khong-co   : governance-detectors.ps1:1109 do ten la roi chi liet
#      (b) -or nuot nhanh  : governance-detectors.ps1:1660 chap ca _end lan closed.md
#      (c) [skip] im lang  : governance-detectors.ps1:1622 / :1882 / mfe-eval.ps1:265
#      => O DAY: moi ten nhan DUNG MOT phan quyet va LUON duoc in ten khi khac OK.
#         Tap vang mat = FLAG "THIEU-TAP", KHONG PHAI skip.
#
#  (5) Pure ASCII (gotcha #30) - do 3 script .ps1 nen: 0/0/0 byte ngoai ASCII,
#      control-duong tren 1 tep .md tieng Viet = 58. Giu nguyen ky luat nay.
#
# Fault-inject: chay voi -RepoRoot <cay-tam> de cay ten lech / go ra, khong dung kho that.

[CmdletBinding()]
param(
    [string]$RepoRoot
)

$ErrorActionPreference = 'Stop'

if (-not $RepoRoot -or $RepoRoot -eq '') {
    $RepoRoot = Split-Path -Parent $PSScriptRoot
}
$RepoRoot = (Resolve-Path -LiteralPath $RepoRoot).Path

# ---------- hinh dang ----------
$RX_KEBAB = '^[a-z0-9]+(-[a-z0-9]+)*$'
$RX_SNAKE = '^[a-z0-9]+(_[a-z0-9]+)*$'
$RX_ONEOFF = '^(s[0-9]+-|plan-)'
$RX_SESSFAM = '^_(tiep|pause|snapshot|day|context-s|mind-s|end)'
# ^ +day @S185 (W-1 day-wake marker _day-<i>.md — reviewer F-6: thieu thi moi marker day = 1 FLAG LECH oan)
$RX_SESSDIR = '^session-[0-9]+$'

# ---------- so ke ----------
$script:Total = 0
$script:Ok = 0
$script:Lech = 0
$script:OneOff = 0
$script:Mien = 0
$script:Pep8 = 0
$script:MissingSets = 0
$script:LechList = @()

# ---------- baseline ky-vong ----------
# NGUON DUY-NHAT = scripts/naming-baseline.json (chu du an chot phuong an (b) @S181, cau 6).
#  (a) Script nay chi DOC. CAM chep so nguoc vao day -- chep nguoc = de nguon-doi,
#      dung thu ma phuong an (b) sinh ra de chan.
#  (b) Nap tu $PSScriptRoot, KHONG phai $RepoRoot: fault-inject chay -RepoRoot <cay-tam>
#      nhung baseline la thuoc tinh cua CHUAN, khong phai cua cay dang quet.
#  (c) Thieu khoa / hong tep => IN LOUD roi tra $null. CAM tra 0: so 0 se lam mau so
#      cua guard A2 (:99) thanh "0/0", va "0/0" doc thanh SACH. Do dung la bay
#      "vang mat trong giong on" ma guard A2 duoc dung len de chan.
$script:BaselinePath = Join-Path $PSScriptRoot 'naming-baseline.json'
$script:Baseline = $null
$script:BaselineUpdated = '(khong ro)'
if (Test-Path -LiteralPath $script:BaselinePath) {
    try {
        $bj = Get-Content -LiteralPath $script:BaselinePath -Raw | ConvertFrom-Json
        $script:Baseline = $bj.sets
        if ($bj._updated) { $script:BaselineUpdated = [string]$bj._updated }
    } catch {
        Write-Host ("FLAG BASELINE-HONG: doc duoc '{0}' nhung khong parse duoc JSON: {1}" -f $script:BaselinePath, $_.Exception.Message) -ForegroundColor Red
    }
} else {
    Write-Host ("FLAG BASELINE-VANG: khong thay '{0}'. Moi nhom se chay KHONG co ky-vong." -f $script:BaselinePath) -ForegroundColor Red
}

function Get-Baseline([string]$Label) {
    if ($null -eq $script:Baseline) { return $null }
    $p = $script:Baseline.PSObject.Properties[$Label]
    if ($null -eq $p) {
        Write-Host ("  FLAG BASELINE-THIEU-KHOA: '{0}' khong co trong naming-baseline.json" -f $Label) -ForegroundColor Red
        return $null
    }
    return [int]$p.Value
}

function Write-Head([string]$t) { Write-Host ''; Write-Host $t -ForegroundColor Cyan }

function Add-Verdict {
    param([string]$Group, [string]$Name, [string]$Verdict, [string]$Note)
    $script:Total++
    switch ($Verdict) {
        'OK'      { $script:Ok++ }
        'PEP8'    { $script:Ok++; $script:Pep8++ }
        'MOT-LAN' { $script:Ok++; $script:OneOff++ }
        'MIEN'    { $script:Mien++ }
        'LECH'    {
            $script:Lech++
            $script:LechList += [pscustomobject]@{ Group = $Group; Name = $Name; Note = $Note }
        }
    }
}

# Quet 1 tap. Tap vang mat => FLAG, KHONG skip im lang (luat 4c).
function Scan-Set {
    param(
        [string]$Label,
        [string]$RelPath,
        # 'Item' = ca tep LAN thu muc. Bat buoc cho scripts/ va docs/governance/ vi
        # tap 231 dem theo don vi "muc" o hai nhom do (bay don-vi: tep != muc).
        [ValidateSet('File', 'Dir', 'Item')][string]$Kind,
        # -1 = khong truyen tay => tra cuu tu naming-baseline.json theo $Label.
        # KHONG dat mac dinh 0: xem ghi chu (c) o khoi nap baseline.
        [int]$Expect = -1,
        [scriptblock]$Rule,
        [string]$Filter = '*',
        [switch]$Recurse
    )

    if ($Expect -lt 0) {
        $b = Get-Baseline $Label
        if ($null -ne $b) { $Expect = $b }
    }
    $hasExpect = ($Expect -ge 0)

    $full = Join-Path $RepoRoot $RelPath
    Write-Head ("--- NHOM: {0}  [{1}]" -f $Label, $RelPath)

    if (-not (Test-Path -LiteralPath $full)) {
        $script:MissingSets++
        Write-Host ("  FLAG THIEU-TAP: khong tim thay '{0}'." -f $RelPath) -ForegroundColor Red
        if ($hasExpect) {
            Write-Host ("  Day KHONG phai [skip]. Tap vang mat => phep do khong ton tai, mau so = 0/{0} ky vong." -f $Expect) -ForegroundColor Red
        } else {
            Write-Host  "  Day KHONG phai [skip]. Tap vang mat => phep do khong ton tai, va KHONG CO ky-vong lam mau so (baseline thieu) => CAM doc thanh sach." -ForegroundColor Red
        }
        Write-Host  "  Nguyen nhan thuong gap: thu muc vua bi doi ten => moi may neo vao no cung mu theo."
        return
    }

    $items = switch ($Kind) {
        'File' { @(Get-ChildItem -LiteralPath $full -File -Filter $Filter -Recurse:$Recurse -ErrorAction SilentlyContinue) }
        'Dir'  { @(Get-ChildItem -LiteralPath $full -Directory -Recurse:$Recurse -ErrorAction SilentlyContinue) }
        'Item' { @(Get-ChildItem -LiteralPath $full -Recurse:$Recurse -ErrorAction SilentlyContinue) }
    }

    $unit = switch ($Kind) { 'File' { 'tep' } 'Dir' { 'thu muc' } 'Item' { 'muc (tep + thu muc)' } }
    $n = $items.Count
    $lo = 0; $lk = 0; $lm = 0; $l1 = 0; $lp = 0
    $rows = @()

    foreach ($it in $items) {
        $v = & $Rule $it
        $verdict = $v[0]; $note = $v[1]
        Add-Verdict -Group $Label -Name $it.Name -Verdict $verdict -Note $note
        switch ($verdict) {
            'OK'      { $lo++ }
            'PEP8'    { $lo++; $lp++ }
            'MOT-LAN' { $lo++; $l1++ }
            'MIEN'    { $lm++ }
            'LECH'    { $lk++ }
        }
        if ($verdict -ne 'OK') { $rows += [pscustomobject]@{ V = $verdict; N = $it.Name; Note = $note } }
    }

    Write-Host ("  mau so: {0} {1}" -f $n, $unit) -NoNewline
    if (-not $hasExpect) {
        Write-Host  "   [!] KHONG CO ky-vong cho nhom nay trong naming-baseline.json" -ForegroundColor Red
    } elseif ($n -ne $Expect) {
        Write-Host ("   [!] lech ky vong {0} (do ngay {1}) - chuan hoac kho da doi, doc lai naming-standard.md" -f $Expect, $script:BaselineUpdated) -ForegroundColor Yellow
    } else { Write-Host '' }

    Write-Host ("  OK {0}/{1} | LECH {2}/{1} | MIEN-theo-luat {3}/{1}" -f $lo, $n, $lk, $lm)
    if ($lp -gt 0) { Write-Host ("    trong OK: {0}/{1} theo PEP-8 (*.py snake_case - DUNG, khong phai troi)" -f $lp, $n) }
    if ($l1 -gt 0) { Write-Host ("    trong OK: {0}/{1} MOT-LAN (tien to s<n>-/plan- = kich ban mot lan, HOP LE)" -f $l1, $n) }

    foreach ($r in $rows) {
        $c = if ($r.V -eq 'LECH') { 'Red' } else { 'DarkGray' }
        Write-Host ("    [{0,-7}] {1}  <- {2}" -f $r.V, $r.N, $r.Note) -ForegroundColor $c
    }
}

Write-Host '=== naming-scan.ps1 - MAY SOI TEN (tang bo may) ===' -ForegroundColor White
Write-Host ("RepoRoot : {0}" -f $RepoRoot)
Write-Host  "Che do   : INFORM-only. LUON exit 0 ke ca khi co co (lai ma thoat = W3b, sau P1=PA-2)."
Write-Host  "Chuan    : docs/governance/naming-standard.md"
Write-Host  "Tap do   : 231 ten vat-bo-may, 0 mien tru VUNG (khong quet 1.545 tep .md - bay-4)."

# 1/7 - vai
Scan-Set -Label 'vai' -RelPath '.claude/agents' -Kind File -Filter '*.md' -Rule {
    param($f)
    if ($f.Name -eq 'README.md') { return @('MIEN', 'quy uoc pho quat (luat L4)') }
    if ($f.BaseName -cmatch $RX_KEBAB) { return @('OK', '') }
    return @('LECH', 'ten vai phai kebab thuan; xem naming-standard.md section 1')
}

# 2/7 - thu muc nhat ky vai
Scan-Set -Label 'nhat-ky-vai' -RelPath '.claude/agent-memory' -Kind Dir -Rule {
    param($d)
    if ($d.Name -cmatch $RX_KEBAB) { return @('OK', '') }
    return @('LECH', 'thu muc nhat ky phai trung ten vai (kebab thuan)')
}

# 3/7 - lenh
Scan-Set -Label 'lenh' -RelPath '.claude/commands' -Kind File -Rule {
    param($f)
    if ($f.Name -eq 'README.md') { return @('MIEN', 'quy uoc pho quat (luat L4)') }
    if ($f.BaseName -cmatch $RX_KEBAB) { return @('OK', '') }
    return @('LECH', 'ten lenh phai kebab; xem naming-standard.md section 7')
}

# 4/7 - kich ban (2 quy uoc ngon ngu, luat L4). Don vi = MUC (co ca thu muc con).
Scan-Set -Label 'kich-ban' -RelPath 'scripts' -Kind Item -Rule {
    param($f)
    if ($f.Name -eq 'README.md') { return @('MIEN', 'quy uoc pho quat (luat L4)') }
    if ($f.Name -eq '__pycache__') { return @('MIEN', 'vat sinh tu dong (luat L4)') }
    if ($f.Extension -eq '.py') {
        if ($f.BaseName -cmatch $RX_SNAKE) { return @('PEP8', 'PEP-8: *.py snake_case la DUNG') }
        return @('LECH', '*.py phai snake_case theo PEP-8')
    }
    if ($f.BaseName -cnotmatch $RX_KEBAB) {
        return @('LECH', 'kich ban khong-phai-.py phai kebab; xem naming-standard.md section 8')
    }
    if ($f.BaseName -cmatch $RX_ONEOFF) {
        return @('MOT-LAN', 'kich ban mot lan thuoc phien/ke hoach - HOP LE, dem rieng')
    }
    return @('OK', '')
}

# 5/7 - tep moc phien. BUOC -Recurse: tep nam trong session-<N>/, khong nam o goc.
Scan-Set -Label 'moc-phien' -RelPath '.claude/sessions' -Kind File -Recurse -Rule {
    param($f)
    if ($f.Name -cmatch $RX_SESSFAM) { return @('OK', '') }
    if ($f.Name -cmatch '^pause-') {
        return @('LECH', 'FORK ho cu: _pause-* la ho chuan. session_ctx.py:349-358 THA (doc ca 2 glob) => fork song mai neu khong ai goi ten')
    }
    if ($f.Name -eq 'closed.md') {
        return @('LECH', 'FORK dau-dong-phien: _end la ho chuan. detectors:1660 THA bang -or => doi sang ten thu BA thi phien da dong bi doc la DANG MO, co khong bao gio ban')
    }
    return @('LECH', 'tep moc phien moi BUOC BAT DAU bang _ ; xem naming-standard.md section 5')
}

# 6/7 - so. Don vi = MUC (co ca thu muc con adap-reports/ adap-requests/).
Scan-Set -Label 'so-governance' -RelPath 'docs/governance' -Kind Item -Rule {
    param($f)
    if ($f.Name -eq 'README.md') { return @('MIEN', 'quy uoc pho quat (luat L4)') }
    if ($f.BaseName -cmatch $RX_KEBAB) { return @('OK', '') }
    return @('LECH', 'VAT LICH SU (thu da gui, mang ngay) - GIU NGUYEN theo luat L1, nhung phai duoc LIET TEN: no la chung nhan nhom nay co 2 ho')
}

# 7/7 - hook
Scan-Set -Label 'hook' -RelPath '.claude/hooks' -Kind File -Rule {
    param($f)
    if ($f.BaseName -cmatch $RX_KEBAB) { return @('OK', '') }
    return @('LECH', 'hook phai kebab')
}

# ---------- bat bien 2 chieu ----------
Write-Head '--- BAT BIEN: .claude/agents/<role>.md  ==  .claude/agent-memory/<role>/ ---'
$agDir = Join-Path $RepoRoot '.claude/agents'
$mmDir = Join-Path $RepoRoot '.claude/agent-memory'
if ((Test-Path -LiteralPath $agDir) -and (Test-Path -LiteralPath $mmDir)) {
    $roles = @(Get-ChildItem -LiteralPath $agDir -File -Filter '*.md' |
               Where-Object { $_.Name -ne 'README.md' } | ForEach-Object { $_.BaseName })
    $dirs = @(Get-ChildItem -LiteralPath $mmDir -Directory | ForEach-Object { $_.Name })
    $noDiary = @($roles | Where-Object { $dirs -notcontains $_ })
    $noPersona = @($dirs | Where-Object { $roles -notcontains $_ })
    Write-Host ("  mau so: {0} vai (tep persona, tru README) / {1} thu muc nhat ky" -f $roles.Count, $dirs.Count)
    Write-Host ("  khop   : {0}/{1}" -f ($roles.Count - $noDiary.Count), $roles.Count)
    if ($noDiary.Count -eq 0) { Write-Host '  vai THIEU thu muc nhat ky : (danh sach rong)' }
    else {
        $script:Lech += $noDiary.Count
        foreach ($r in $noDiary) {
            Write-Host ("  FLAG vai THIEU nhat ky: {0}  <- mfe-eval.ps1:264-267 se in 'N/A (no persistent diary)' va LOAI vai khoi phep do" -f $r) -ForegroundColor Red
            $script:LechList += [pscustomobject]@{ Group = 'bat-bien'; Name = $r; Note = 'thieu thu muc nhat ky' }
        }
    }
    if ($noPersona.Count -eq 0) { Write-Host '  nhat ky THUA (khong co persona): (danh sach rong)' }
    else {
        $script:Lech += $noPersona.Count
        foreach ($r in $noPersona) {
            Write-Host ("  FLAG nhat ky THUA: {0}  <- detectors:1109 se xep vao `$unmapped (LIET, KHONG CO)" -f $r) -ForegroundColor Red
            $script:LechList += [pscustomobject]@{ Group = 'bat-bien'; Name = $r; Note = 'thua thu muc nhat ky' }
        }
    }
} else {
    $script:MissingSets++
    Write-Host '  FLAG THIEU-TAP: thieu .claude/agents hoac .claude/agent-memory => bat bien KHONG DO DUOC.' -ForegroundColor Red
}

# ---------- khai tuong minh cai NGOAI tap ----------
Write-Head '--- NGOAI TAP 231 (khai tuong minh - KHONG phai [skip]) ---'
$sessRoot = Join-Path $RepoRoot '.claude/sessions'
if (Test-Path -LiteralPath $sessRoot) {
    $sd = @(Get-ChildItem -LiteralPath $sessRoot -Directory)
    $sdOk = @($sd | Where-Object { $_.Name -cmatch $RX_SESSDIR })
    Write-Host ("  thu muc phien: {0}/{1} dat hinh dang ^session-<so>$" -f $sdOk.Count, $sd.Count)
    Write-Host  "  CO CHU DICH nam ngoai tap 231: giu mau so 231 da thoa thuan, va nhom nay DA co may ep"
    Write-Host  "  (governance-detectors.ps1:1639 + session_ctx.py:133 + 2 ban session-scaffold)."
    $bad = @($sd | Where-Object { $_.Name -cnotmatch $RX_SESSDIR })
    foreach ($b in $bad) { Write-Host ("    [LECH-ngoai-tap] {0}" -f $b.Name) -ForegroundColor Yellow }
} else {
    Write-Host '  FLAG: .claude/sessions vang mat.' -ForegroundColor Red
}

# ---------- tong ----------
Write-Head '=== TONG ==='
Write-Host ("  mau so TONG        : {0} ten vat-bo-may" -f $script:Total)
Write-Host  "    goc 231 (do 2026-08-07 TRUOC wave W1) = 27 vai + 26 nhat ky + 19 lenh + 53 kich ban"
Write-Host  "                                          + 90 moc phien + 15 so + 1 hook"
Write-Host  "    +2 vat chinh W1 de ra: scripts/naming-scan.ps1 va docs/governance/naming-standard.md"
Write-Host  "    => 233 sau W1. Khai ro de khong ai doc 233 thanh 'kho phinh ra' (bay-6: so do giua chung)."
Write-Host ("  OK                 : {0}/{1}" -f $script:Ok, $script:Total)
Write-Host ("    trong do PEP-8   : {0}/{1}  (*.py snake - DUNG theo luat ngon ngu, khong phai troi)" -f $script:Pep8, $script:Total)
Write-Host ("    trong do MOT-LAN : {0}/{1}  (kich ban mot lan - HOP LE, tin hieu ton kho chu khong phai vi pham)" -f $script:OneOff, $script:Total)
Write-Host ("  MIEN theo luat L4  : {0}/{1}  (in ten o tung nhom - mien tru im lang va loi im lang trong giong het nhau)" -f $script:Mien, $script:Total)
if ($script:Lech -gt 0) {
    Write-Host ("  LECH               : {0}/{1}" -f $script:Lech, $script:Total) -ForegroundColor Red
} else {
    Write-Host ("  LECH               : 0/{0}" -f $script:Total) -ForegroundColor Green
    Write-Host  "  [!] 0 hit chi co nghia neu mau so tren KHAC 0 va tap do KHONG mien tru vung." -ForegroundColor Yellow
}
if ($script:MissingSets -gt 0) {
    Write-Host ("  TAP VANG MAT       : {0}  <- moi tap vang lam phep do BIEN MAT, khong phai 'sach'" -f $script:MissingSets) -ForegroundColor Red
}

if ($script:LechList.Count -gt 0) {
    Write-Host ''
    Write-Host '  Danh sach LECH (tung ten - cam nen thanh khoang):' -ForegroundColor Red
    foreach ($x in $script:LechList) { Write-Host ("    - [{0}] {1}" -f $x.Group, $x.Name) }
}

Write-Host ''
Write-Host '  Ma thoat: 0 (INFORM-only theo hop dong muc 1). Co o tren KHONG lai ma thoat.'
Write-Host '  Lai ma thoat thuoc wave W3b, sau khi chu du an chot phan loai co theo PA-2.'
exit 0
