/**
 * Hook Pattern Matcher
 *
 * Provides pattern matching functionality for hook tool name matching.
 * Supports exact matching, wildcard patterns, and pipe-separated alternatives.
 */
import { minimatch } from "minimatch";
export class HookMatcher {
    /**
     * Test if pattern matches tool name
     * Supports multiple matching strategies:
     * - Exact matching: "Edit" matches "Edit"
     * - Pipe alternatives: "Edit|Write" matches "Edit" or "Write"
     * - Glob patterns: "Edit*" matches "EditFile", "EditText", etc.
     * - Case insensitive matching
     */
    matches(pattern, toolName) {
        if (!pattern || !toolName)
            return false;
        // Handle pipe-separated alternatives (e.g., "Edit|Write|Delete")
        if (pattern.includes("|")) {
            const alternatives = pattern.split("|").map((alt) => alt.trim());
            return alternatives.some((alt) => this.matchesSingle(alt, toolName));
        }
        return this.matchesSingle(pattern, toolName);
    }
    /**
     * Match a single pattern against tool name
     */
    matchesSingle(pattern, toolName) {
        // Exact match (case insensitive)
        if (pattern.toLowerCase() === toolName.toLowerCase()) {
            return true;
        }
        // Glob pattern matching using minimatch
        try {
            return minimatch(toolName, pattern, {
                nocase: true, // Case insensitive
                noglobstar: false, // Allow ** patterns
                nonegate: true, // Disable negation for security
            });
        }
        catch {
            // Invalid pattern, fall back to exact match
            return false;
        }
    }
    /**
     * Validate pattern syntax
     */
    isValidPattern(pattern) {
        if (!pattern || typeof pattern !== "string")
            return false;
        // Empty pattern is invalid
        if (pattern.trim().length === 0)
            return false;
        // Handle pipe-separated alternatives
        if (pattern.includes("|")) {
            const alternatives = pattern.split("|").map((alt) => alt.trim());
            return (alternatives.length > 0 &&
                alternatives.every((alt) => alt.length > 0 && this.isValidSinglePattern(alt)));
        }
        return this.isValidSinglePattern(pattern);
    }
    /**
     * Validate single pattern syntax
     */
    isValidSinglePattern(pattern) {
        // Basic validation - non-empty string
        if (!pattern || pattern.trim().length === 0)
            return false;
        // Check for dangerous characters that could be used for command injection
        // Note: [ ] are allowed for glob patterns
        const dangerousChars = /[;&|`$(){}><]/;
        if (dangerousChars.test(pattern))
            return false;
        // Validate glob pattern syntax using minimatch
        try {
            // Test with a dummy string to validate pattern
            minimatch("test", pattern, { nocase: true });
            return true;
        }
        catch {
            return false;
        }
    }
    /**
     * Get pattern type for optimization
     */
    getPatternType(pattern) {
        if (!pattern)
            return "exact";
        // Check for pipe alternatives first
        if (pattern.includes("|")) {
            return "alternatives";
        }
        // Check for regex patterns first (before glob check)
        if (pattern.startsWith("/") &&
            pattern.endsWith("/") &&
            pattern.length > 2) {
            return "regex";
        }
        // Check for glob patterns
        if (pattern.includes("*") ||
            pattern.includes("?") ||
            pattern.includes("[")) {
            return "glob";
        }
        return "exact";
    }
    /**
     * Get all tool names that would match this pattern from a given list
     * Useful for testing and validation
     */
    getMatches(pattern, tools) {
        return tools.filter((toolName) => this.matches(pattern, toolName));
    }
    /**
     * Optimize pattern for repeated matching
     * Returns a compiled matcher function for performance
     */
    compile(pattern) {
        if (!this.isValidPattern(pattern)) {
            return () => false;
        }
        const patternType = this.getPatternType(pattern);
        switch (patternType) {
            case "exact": {
                const lowerPattern = pattern.toLowerCase();
                return (toolName) => toolName.toLowerCase() === lowerPattern;
            }
            case "alternatives": {
                const alternatives = pattern
                    .split("|")
                    .map((alt) => alt.trim().toLowerCase());
                return (toolName) => {
                    const lowerTool = toolName.toLowerCase();
                    return alternatives.some((alt) => lowerTool === alt || minimatch(toolName, alt, { nocase: true }));
                };
            }
            case "glob":
                return (toolName) => minimatch(toolName, pattern, { nocase: true });
            default:
                return (toolName) => this.matches(pattern, toolName);
        }
    }
}
