#!/usr/bin/env pwsh
<#
.SYNOPSIS
    Check that CLI command switch statements handle all action strings from ActionExtensions.cs

.DESCRIPTION
    This script verifies that each CLI Command's "action switch" statement handles all the
    action strings defined in ActionExtensions.cs for the corresponding enum. This prevents
    bugs like ChartCommand missing "create-from-table" case (found 2026-02-01).

.EXAMPLE
    .\scripts\check-cli-action-coverage.ps1
    .\scripts\check-cli-action-coverage.ps1 -Verbose

.NOTES
    Created to catch missing CLI switch cases that check-cli-coverage.ps1 misses.
    That script only checks if a CLI command EXISTS for each enum.
    This script checks if the CLI command HANDLES all actions for that enum.
#>

param(
    [switch]$Verbose
)

$ErrorActionPreference = "Stop"
$rootDir = Split-Path -Parent $PSScriptRoot

Write-Host "CLI Action Switch Coverage Check" -ForegroundColor Cyan
Write-Host "====================================" -ForegroundColor Cyan
Write-Host ""

$actionExtensionsPath = Join-Path $rootDir "src\ExcelMcp.Core\Models\Actions\ActionExtensions.cs"
$cliCommandsDir = Join-Path $rootDir "src\ExcelMcp.CLI\Commands"

if (-not (Test-Path $actionExtensionsPath)) {
    Write-Host "ActionExtensions.cs not found: $actionExtensionsPath" -ForegroundColor Red
    exit 1
}

if (-not (Test-Path $cliCommandsDir)) {
    Write-Host "CLI Commands directory not found: $cliCommandsDir" -ForegroundColor Red
    exit 1
}

# Map enum names to CLI command file names
# Pattern: ChartAction -> ChartCommand.cs
$enumToCliCommand = @{
    # Direct mappings (enum name matches command name)
    "ChartAction" = "ChartCommand.cs"
    "ChartConfigAction" = "ChartConfigCommand.cs"
    "ConnectionAction" = "ConnectionCommand.cs"
    "ConditionalFormatAction" = "ConditionalFormatCommand.cs"
    "DataModelAction" = "DataModelCommand.cs"
    "DataModelRelAction" = "DataModelRelCommand.cs"
    "NamedRangeAction" = "NamedRangeCommand.cs"
    "PowerQueryAction" = "PowerQueryCommand.cs"
    "PivotTableAction" = "PivotTableCommand.cs"
    "SlicerAction" = "SlicerCommand.cs"
    "TableAction" = "TableCommand.cs"
    "VbaAction" = "VbaCommand.cs"

    # Naming exceptions
    "WorksheetAction" = "SheetCommand.cs"
    "WorksheetStyleAction" = "SheetCommand.cs"  # Style actions handled via sheet command with --style flag

    # Range variants all use RangeCommand
    "RangeAction" = "RangeCommand.cs"
    "RangeEditAction" = "RangeCommand.cs"
    "RangeFormatAction" = "RangeCommand.cs"
    "RangeLinkAction" = "RangeCommand.cs"

    # PivotTable variants
    "PivotTableFieldAction" = "PivotTableCommand.cs"
    "PivotTableCalcAction" = "PivotTableCommand.cs"

    # Table variants
    "TableColumnAction" = "TableCommand.cs"
}

# Enums that don't have direct CLI switch coverage (handled differently)
$excludedEnums = @(
    "FileAction"  # CLI uses session subcommands, not action switch
)

# Actions that can safely fall through to default (no specific args required)
# ALL other actions MUST have explicit switch cases
$actionsAllowingDefault = @{
    "ChartAction" = @("list", "read")
    "ChartConfigAction" = @()  # All require specific args
    "PowerQueryAction" = @("list", "refresh-all")
    "WorksheetAction" = @("list")
    "WorksheetStyleAction" = @()  # All require specific args
    "TableAction" = @("list")
    "TableColumnAction" = @()  # All require specific args
    "VbaAction" = @("list")
    "ConnectionAction" = @("list")
    "DataModelAction" = @("list-tables", "read-info", "refresh")
    "DataModelRelAction" = @("list-relationships")
    "NamedRangeAction" = @("list")
    "SlicerAction" = @("list-slicers", "list-table-slicers")
    "ConditionalFormatAction" = @()  # All require specific args
    "PivotTableAction" = @("list")
    "PivotTableFieldAction" = @()  # All require specific args
    "PivotTableCalcAction" = @()  # All require specific args
    "RangeAction" = @("get-used-range")
    "RangeEditAction" = @()  # All require specific args
    "RangeFormatAction" = @()  # All require specific args
    "RangeLinkAction" = @()  # All require specific args
}

# Parse ActionExtensions.cs to extract action strings for each enum
function Get-ActionStringsFromExtensions {
    param([string]$Content)

    $result = @{}

    # Match each ToActionString method and extract enum name and action mappings
    # Pattern: public static string ToActionString(this EnumName action) => action switch { ... };
    $methodPattern = 'public\s+static\s+string\s+ToActionString\(this\s+(\w+Action)\s+action\)\s*=>\s*action\s+switch\s*\{([^}]+)\}'
    $matches = [regex]::Matches($Content, $methodPattern, [System.Text.RegularExpressions.RegexOptions]::Singleline)

    foreach ($match in $matches) {
        $enumName = $match.Groups[1].Value
        $switchBody = $match.Groups[2].Value

        # Extract action strings: EnumName.Value => "action-string"
        $actionPattern = '\w+\.\w+\s*=>\s*"([^"]+)"'
        $actionMatches = [regex]::Matches($switchBody, $actionPattern)

        $actions = @()
        foreach ($actionMatch in $actionMatches) {
            $actions += $actionMatch.Groups[1].Value
        }

        $result[$enumName] = $actions
    }

    return $result
}

# Parse CLI Command file to extract handled action strings from switch
function Get-HandledActionsFromCommand {
    param([string]$FilePath)

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

    $content = Get-Content $FilePath -Raw

    # Find the "action switch" block
    # Pattern: object? args = action switch { ... };
    $switchPattern = 'object\?\s+args\s*=\s*action\s+switch\s*\{([^;]+)\};'
    $match = [regex]::Match($content, $switchPattern, [System.Text.RegularExpressions.RegexOptions]::Singleline)

    if (-not $match.Success) {
        return @()
    }

    $switchBody = $match.Groups[1].Value

    # Extract action strings: "action-string" => ...
    $actionPattern = '"([^"]+)"\s*=>'
    $actionMatches = [regex]::Matches($switchBody, $actionPattern)

    $actions = @()
    foreach ($actionMatch in $actionMatches) {
        $actions += $actionMatch.Groups[1].Value
    }

    return $actions
}

# Read ActionExtensions.cs
$extensionsContent = Get-Content $actionExtensionsPath -Raw
$enumActionStrings = Get-ActionStringsFromExtensions -Content $extensionsContent

Write-Host "Found $($enumActionStrings.Count) action enums in ActionExtensions.cs" -ForegroundColor Gray
Write-Host ""

$totalMissing = 0
$totalChecked = 0

foreach ($enumName in $enumActionStrings.Keys | Sort-Object) {
    # Skip excluded enums
    if ($excludedEnums -contains $enumName) {
        if ($Verbose) {
            Write-Host "$enumName -> (excluded, CLI handles differently)" -ForegroundColor Gray
        }
        continue
    }

    # Get CLI command file
    if (-not $enumToCliCommand.ContainsKey($enumName)) {
        Write-Host "$enumName -> No CLI mapping defined (add to `$enumToCliCommand)" -ForegroundColor Yellow
        continue
    }

    $commandFile = $enumToCliCommand[$enumName]
    $commandPath = Join-Path $cliCommandsDir $commandFile

    if (-not (Test-Path $commandPath)) {
        Write-Host "$enumName -> CLI file not found: $commandFile" -ForegroundColor Yellow
        continue
    }

    # Get expected and actual actions
    $expectedActions = $enumActionStrings[$enumName]
    $handledActions = Get-HandledActionsFromCommand -FilePath $commandPath

    # Filter out actions that can safely fall through to default (list, read, etc.)
    if ($actionsAllowingDefault.ContainsKey($enumName)) {
        $allowedDefaults = $actionsAllowingDefault[$enumName]
        $expectedActions = $expectedActions | Where-Object { $_ -notin $allowedDefaults }
    }

    # Find missing actions
    $missingActions = $expectedActions | Where-Object { $_ -notin $handledActions }

    $totalChecked++

    if ($missingActions.Count -gt 0) {
        $totalMissing += $missingActions.Count
        Write-Host "$enumName -> $commandFile" -ForegroundColor Red
        foreach ($missing in $missingActions) {
            Write-Host "     Missing: `"$missing`"" -ForegroundColor Yellow
        }
    } else {
        if ($Verbose) {
            Write-Host "$enumName -> $commandFile ($($expectedActions.Count) actions)" -ForegroundColor Green
        }
    }
}

Write-Host ""

if ($totalMissing -gt 0) {
    Write-Host "MISSING CLI SWITCH CASES DETECTED!" -ForegroundColor Red
    Write-Host "   Total missing: $totalMissing cases across $totalChecked enums checked" -ForegroundColor Yellow
    Write-Host ""
    Write-Host "Action Required:" -ForegroundColor Yellow
    Write-Host "  1. Add missing case to the CLI command's 'action switch' statement" -ForegroundColor Yellow
    Write-Host "  2. Include all required args for that action (match daemon's *Args class)" -ForegroundColor Yellow
    Write-Host "  3. Example: `"create-from-table`" => new { tableName = settings.TableName, ... }" -ForegroundColor Yellow
    Write-Host ""
    exit 1
}

Write-Host "All $totalChecked CLI commands handle their action strings!" -ForegroundColor Green
exit 0
