[CmdletBinding()]
param(
    [switch]$Json
)

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

function Clean-Alias {
    param(
        [Parameter(Mandatory = $false)]
        [string]$Value
    )

    if ([string]::IsNullOrWhiteSpace($Value)) {
        return ""
    }

    $alias = ($Value -replace [char]7, "").Trim()
    $match = [regex]::Match($alias, 'fc\.[A-Za-z0-9_.-]+')
    if ($match.Success) {
        return $match.Value
    }
    return ""
}

function Get-UniqueAliases {
    param(
        [string[]]$Items
    )

    if ($null -eq $Items -or $Items.Count -eq 0) {
        return @()
    }

    $set = New-Object 'System.Collections.Generic.HashSet[string]'
    foreach ($item in $Items) {
        if (-not [string]::IsNullOrWhiteSpace($item)) {
            [void]$set.Add($item)
        }
    }
    $output = New-Object string[] $set.Count
    $set.CopyTo($output)
    return $output
}

function Get-DocsAliases {
    param(
        [Parameter(Mandatory = $true)]
        [string]$ComponentsDir
    )

    $docs = Get-ChildItem -Path $ComponentsDir -File -Filter "*.md" | Where-Object { $_.Name -ne "INDEX.md" }
    $bell = [char]7

    $aliases = @()
    $docsWithAiParseNotes = 0
    $docsWithBellChar = 0
    $docsWithAliasFrontmatter = 0

    foreach ($doc in $docs) {
        $content = Get-Content -Path $doc.FullName -Raw

        if ($content -match '(?m)^##\s+AI Parse Notes\b') {
            $docsWithAiParseNotes++
        }

        if ($content.Contains($bell)) {
            $docsWithBellChar++
        }

        $frontmatter = [regex]::Match($content, '(?ms)^---\r?\n(.*?)\r?\n---')
        if ($frontmatter.Success) {
            $aliasMatch = [regex]::Match($frontmatter.Groups[1].Value, '(?m)^\s*alias\s*:\s*(.+?)\s*$')
            if ($aliasMatch.Success) {
                $docsWithAliasFrontmatter++
                $alias = Clean-Alias -Value $aliasMatch.Groups[1].Value
                if ($alias -like "fc.*") {
                    $aliases += $alias
                }
            }
        }
    }

    return [pscustomobject]@{
        Docs                      = $docs
        Aliases                   = @(Get-UniqueAliases -Items $aliases)
        DocsWithAiParseNotes      = $docsWithAiParseNotes
        DocsWithBellChar          = $docsWithBellChar
        DocsWithAliasFrontmatter  = $docsWithAliasFrontmatter
    }
}

function Get-RegistryAliases {
    param(
        [Parameter(Mandatory = $true)]
        [string]$RegistryFile
    )

    $content = Get-Content -Path $RegistryFile -Raw
    $sectionStart = [regex]::Match($content, '(?m)^##\s+Component Alias Registry\s*$')
    if (-not $sectionStart.Success) {
        return @()
    }

    $rest = $content.Substring($sectionStart.Index + $sectionStart.Length)
    $nextSection = [regex]::Match($rest, '(?m)^##\s+')
    if ($nextSection.Success) {
        $rest = $rest.Substring(0, $nextSection.Index)
    }

    $aliases = @()
    $lines = $rest -split "\r?\n"
    foreach ($line in $lines) {
        if (-not $line.Trim().StartsWith("|")) { continue }
        if ($line -notmatch "fc\.") { continue }

        $cells = $line -split "\|"
        if ($cells.Length -lt 2) { continue }
        $firstCell = $cells[1].Trim()
        $aliasMatch = [regex]::Match($firstCell, 'fc\.[A-Za-z0-9_.-]+')
        if ($aliasMatch.Success) {
            $aliases += $aliasMatch.Value
        }
    }

    if ($aliases.Count -eq 0) {
        return @()
    }
    return @(Get-UniqueAliases -Items $aliases)
}

function Get-IndexAliases {
    param(
        [Parameter(Mandatory = $true)]
        [string]$IndexFile
    )

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

    $lines = Get-Content -Path $IndexFile
    $aliases = @()
    foreach ($line in $lines) {
        if (-not $line.Trim().StartsWith("|")) { continue }
        if ($line -notmatch "fc\.") { continue }
        $cells = $line -split "\|"
        if ($cells.Length -lt 2) { continue }
        $aliasMatch = [regex]::Match($cells[1], 'fc\.[A-Za-z0-9_.-]+')
        if ($aliasMatch.Success) {
            $aliases += $aliasMatch.Value
        }
    }

    if ($aliases.Count -eq 0) {
        return @()
    }
    return @(Get-UniqueAliases -Items $aliases)
}

$scriptDir = Split-Path -Path $MyInvocation.MyCommand.Path -Parent
$componentsDir = Join-Path -Path $scriptDir -ChildPath "components"
$indexFile = Join-Path -Path $componentsDir -ChildPath "INDEX.md"
$registryFile = [System.IO.Path]::GetFullPath((Join-Path -Path $scriptDir -ChildPath "..\fluent-mystique-validate\SKILL.md"))

if (-not (Test-Path -Path $componentsDir)) {
    throw "Components directory not found: $componentsDir"
}
if (-not (Test-Path -Path $registryFile)) {
    throw "Registry file not found: $registryFile"
}
if (-not (Test-Path -Path $indexFile)) {
    throw "Index file not found: $indexFile"
}

$docsData = Get-DocsAliases -ComponentsDir $componentsDir
$registryAliases = @(Get-RegistryAliases -RegistryFile $registryFile)
$indexAliases = @(Get-IndexAliases -IndexFile $indexFile)

$registryOnly = @($registryAliases | Where-Object { $_ -notin $docsData.Aliases } | Sort-Object)
$docsOnly = @($docsData.Aliases | Where-Object { $_ -notin $registryAliases } | Sort-Object)
$indexOnly = @($indexAliases | Where-Object { $_ -notin $docsData.Aliases } | Sort-Object)
$docsMissingInIndex = @($docsData.Aliases | Where-Object { $_ -notin $indexAliases } | Sort-Object)

$summary = [pscustomobject]@{
    componentDocs              = $docsData.Docs.Count
    docsWithAiParseNotes       = $docsData.DocsWithAiParseNotes
    docsWithBellChar           = $docsData.DocsWithBellChar
    docsWithAliasFrontmatter   = $docsData.DocsWithAliasFrontmatter
    indexRows                  = $indexAliases.Count
    registryAliases            = $registryAliases.Count
    documentedAliases          = $docsData.Aliases.Count
    missingInDocsCount         = $registryOnly.Count
    extraInDocsCount           = $docsOnly.Count
    indexOnlyCount             = $indexOnly.Count
    docsMissingInIndexCount    = $docsMissingInIndex.Count
}

$report = [pscustomobject]@{
    summary            = $summary
    missingInDocs      = $registryOnly
    extraInDocs        = $docsOnly
    indexOnly          = $indexOnly
    docsMissingInIndex = $docsMissingInIndex
}

if ($Json) {
    $report | ConvertTo-Json -Depth 5
} else {
    Write-Host "Mystique Docs Validation"
    Write-Host "========================"
    Write-Host ("componentDocs            : {0}" -f $summary.componentDocs)
    Write-Host ("docsWithAiParseNotes     : {0}" -f $summary.docsWithAiParseNotes)
    Write-Host ("docsWithBellChar         : {0}" -f $summary.docsWithBellChar)
    Write-Host ("docsWithAliasFrontmatter : {0}" -f $summary.docsWithAliasFrontmatter)
    Write-Host ("indexRows                : {0}" -f $summary.indexRows)
    Write-Host ("registryAliases          : {0}" -f $summary.registryAliases)
    Write-Host ("documentedAliases        : {0}" -f $summary.documentedAliases)
    Write-Host ("missingInDocsCount       : {0}" -f $summary.missingInDocsCount)
    Write-Host ("extraInDocsCount         : {0}" -f $summary.extraInDocsCount)
    Write-Host ("indexOnlyCount           : {0}" -f $summary.indexOnlyCount)
    Write-Host ("docsMissingInIndexCount  : {0}" -f $summary.docsMissingInIndexCount)

    if ($registryOnly.Count -gt 0) {
        Write-Host ""
        Write-Host "Missing in docs:"
        $registryOnly | ForEach-Object { Write-Host (" - {0}" -f $_) }
    }
    if ($docsOnly.Count -gt 0) {
        Write-Host ""
        Write-Host "Extra in docs (not in registry):"
        $docsOnly | ForEach-Object { Write-Host (" - {0}" -f $_) }
    }
    if ($indexOnly.Count -gt 0) {
        Write-Host ""
        Write-Host "Index-only aliases:"
        $indexOnly | ForEach-Object { Write-Host (" - {0}" -f $_) }
    }
    if ($docsMissingInIndex.Count -gt 0) {
        Write-Host ""
        Write-Host "Docs missing from index:"
        $docsMissingInIndex | ForEach-Object { Write-Host (" - {0}" -f $_) }
    }
}

$failed = $false
if ($summary.componentDocs -ne $summary.docsWithAiParseNotes) { $failed = $true }
if ($summary.docsWithBellChar -gt 0) { $failed = $true }
if ($summary.componentDocs -ne $summary.docsWithAliasFrontmatter) { $failed = $true }
if ($summary.missingInDocsCount -gt 0) { $failed = $true }
if ($summary.extraInDocsCount -gt 0) { $failed = $true }
if ($summary.indexOnlyCount -gt 0) { $failed = $true }
if ($summary.docsMissingInIndexCount -gt 0) { $failed = $true }

if ($failed) {
    exit 1
}

exit 0
