const OVER_ENGINEERING_PATTERNS = [
    {
        type: 'premature-abstraction',
        pattern: /para futuros casos|for future (use|cases)|extensible para|gen[eé]rico|generic framework|plugin system|registry pattern/i,
        description: 'Abstraction for hypothetical future cases not yet needed',
    },
    {
        type: 'n-dimensional-classifier',
        pattern: /\b(size|complexity|maturity|teamSize|specDensity|dimension)\b.*\b(size|complexity|maturity|teamSize|specDensity|dimension)\b.*\b(size|complexity|maturity|teamSize|specDensity|dimension)\b/i,
        description: 'Multi-dimensional classifier (3+ axes) — likely reducible to 1-2 dimensions',
    },
    {
        type: 'unnecessary-indirection',
        pattern: /factory of|registry of registr|manager of manager|adapter of adapter|interface.*interface/i,
        description: 'Unnecessary indirection layers',
    },
    {
        type: 'yagni-violation',
        pattern: /we might need|podr[ií]amos necesitar|could be used|puede ser [uú]til en el futuro|for now.*but later|aunque ahora solo/i,
        description: 'YAGNI violation — building for hypothetical needs',
    },
    {
        type: 'configurable-without-users',
        pattern: /configurable|personalizable|allow.*override|permit.*customize/i,
        description: 'Configurability without evidence of users needing different configs',
    },
    {
        type: 'scale-without-evidence',
        pattern: /para escalar|to scale|highly scalable|horizontally scalable|distributed/i,
        description: 'Scalability design without evidence the current problem requires it',
    },
];
/** Detect interface/type definitions with many optional fields */
function detectExcessiveOptionals(text) {
    const interfaceMatches = text.match(/interface\s+\w+\s*\{([^}]+)\}/g) ?? [];
    for (const iface of interfaceMatches) {
        const optionalCount = (iface.match(/\?:/g) ?? []).length;
        if (optionalCount >= 4) {
            return {
                type: 'excessive-optionals',
                description: `Interface with ${String(optionalCount)} optional fields — likely over-specified`,
                evidence: iface.substring(0, 100),
            };
        }
    }
    return null;
}
/** Calculate effort vs value ROI */
function calculateRoi(estimatedHours, text) {
    const highValueSignals = /save.*\$|ahorro.*\$|revenue|ingresos|critical|cr[ií]tico|blocking|bloquea/i.test(text);
    const lowValueSignals = /nice to have|ser[ií]a bueno|optional|opcional|minor|menor|tip|hint/i.test(text);
    if (estimatedHours > 12 && lowValueSignals) {
        return 'low';
    }
    if (estimatedHours > 20 && !highValueSignals) {
        return 'low';
    }
    if (estimatedHours <= 8 || highValueSignals) {
        return 'high';
    }
    return 'medium';
}
/** Generate a simple alternative suggestion based on detected signals */
function suggestSimpleAlternative(signals) {
    if (signals.length === 0) {
        return null;
    }
    const suggestions = [];
    if (signals.some((s) => s.type === 'n-dimensional-classifier')) {
        suggestions.push('Replace multi-dimensional classifier with a single binary or ternary rule');
    }
    if (signals.some((s) => s.type === 'premature-abstraction')) {
        suggestions.push('Implement the specific case first; abstract only when a second case emerges');
    }
    if (signals.some((s) => s.type === 'configurable-without-users')) {
        suggestions.push('Hardcode the sensible default; add config only when a user requests a different value');
    }
    if (signals.some((s) => s.type === 'unnecessary-indirection')) {
        suggestions.push('Flatten the indirection layers into a single direct function');
    }
    if (signals.some((s) => s.type === 'yagni-violation')) {
        suggestions.push('Remove the hypothetical future case; add it only when a real use case exists');
    }
    if (signals.some((s) => s.type === 'scale-without-evidence')) {
        suggestions.push('Start with a simple single-instance design; scale only when load evidence demands it');
    }
    return suggestions.length > 0 ? suggestions.join('. ') : null;
}
/**
 * Analyzes a spec description/criteria text for over-engineering signals.
 * Returns a simplicity score (0-100), detected signals, and a recommended alternative.
 * Never throws — errors result in a default "approve" result.
 */
export function analyzeSimplicity(specText, estimatedHours = 8) {
    const signals = [];
    // Run pattern-based detection
    for (const { type, pattern, description } of OVER_ENGINEERING_PATTERNS) {
        const match = specText.match(pattern);
        if (match) {
            signals.push({ type, description, evidence: match[0] });
        }
    }
    // Check for excessive optionals in interface definitions
    const optionalSignal = detectExcessiveOptionals(specText);
    if (optionalSignal) {
        signals.push(optionalSignal);
    }
    // Calculate score: start at 100, diminishing deductions per signal (first = largest)
    const deductionPerSignal = [20, 15, 12, 10, 8, 7, 6, 5];
    const score = Math.max(0, 100 - signals.reduce((acc, _, i) => acc + (deductionPerSignal[i] ?? 5), 0));
    const roi = calculateRoi(estimatedHours, specText);
    const simpleAlternative = suggestSimpleAlternative(signals);
    const recommendation = score < 60 && roi === 'low' ? 'simplify' : score < 75 ? 'review' : 'approve';
    return {
        score,
        signals,
        simpleAlternative,
        effortVsValue: { estimatedHours, roi },
        recommendation,
    };
}
//# sourceMappingURL=simplicity-detector.js.map