/**
 * Severity Classifier
 *
 * Classifies discrepancy severity to determine appropriate action.
 * Conservative by default: when uncertain, classify higher severity.
 *
 * @module core/discrepancy/severity-classifier
 */
import { consoleLogger } from '../../utils/logger.js';
/**
 * Classifies discrepancy severity based on change type and details.
 */
export class SeverityClassifier {
    constructor(options = {}) {
        this.logger = options.logger ?? consoleLogger;
        this.config = {
            conservative: options.config?.conservative ?? true,
            strictRemovals: options.config?.strictRemovals ?? true,
        };
    }
    /**
     * Classify the severity of a discrepancy.
     */
    classify(change) {
        // Removal = breaking (might break consumers)
        if (change.category === 'removed') {
            return this.classifyRemoval(change);
        }
        // Addition = major (new undocumented functionality)
        if (change.category === 'added') {
            return this.classifyAddition(change);
        }
        // Modification = depends on what changed
        return this.classifyModification(change);
    }
    classifyRemoval(change) {
        if (this.config.strictRemovals) {
            return {
                severity: 'breaking',
                reason: `${change.itemType} removed: ${change.specValue}`,
                confidence: 'high',
            };
        }
        // Type definitions are major, all other removals are breaking
        if (change.itemType === 'type-definition') {
            return {
                severity: 'major',
                reason: `Type definition removed: ${change.specValue}`,
                confidence: 'medium',
            };
        }
        const itemLabels = {
            'api-route': 'API route',
            'function-signature': 'Exported function',
            'type-definition': 'Type definition',
        };
        return {
            severity: 'breaking',
            reason: `${itemLabels[change.itemType]} removed: ${change.specValue}`,
            confidence: 'high',
        };
    }
    classifyAddition(change) {
        // Types are minor (usually supporting types), all others are major
        if (change.itemType === 'type-definition') {
            return {
                severity: 'minor',
                reason: `New type definition not documented: ${change.codeValue}`,
                confidence: 'medium',
            };
        }
        const itemLabels = {
            'api-route': 'API route',
            'function-signature': 'exported function',
            'type-definition': 'type definition',
        };
        return {
            severity: 'major',
            reason: `New ${itemLabels[change.itemType]} not documented: ${change.codeValue}`,
            confidence: 'high',
        };
    }
    classifyModification(change) {
        const description = change.description?.toLowerCase() ?? '';
        // Check for trivial changes
        if (this.isTrivialChange(change.specValue, change.codeValue, description)) {
            return {
                severity: 'trivial',
                reason: 'Minor formatting or documentation change',
                confidence: 'high',
            };
        }
        // Check for breaking signature changes
        if (this.isBreakingSignatureChange(change)) {
            return {
                severity: 'breaking',
                reason: this.getBreakingChangeReason(change),
                confidence: 'high',
            };
        }
        // API route path changes
        if (change.itemType === 'api-route') {
            return this.classifyApiRouteChange(change);
        }
        // Function signature changes
        if (change.itemType === 'function-signature') {
            return this.classifyFunctionChange(change);
        }
        // Default to minor for modifications
        return {
            severity: this.config.conservative ? 'minor' : 'trivial',
            reason: 'Modification detected',
            confidence: 'low',
        };
    }
    isTrivialChange(specValue, codeValue, description) {
        // If normalized values are same, it's just formatting
        if (this.normalize(specValue) === this.normalize(codeValue)) {
            return true;
        }
        // Check for typo indicators in description
        return description.includes('typo') || description.includes('whitespace');
    }
    normalize(value) {
        return value
            .toLowerCase()
            .replace(/\s+/g, ' ')
            .replace(/['"]/g, '')
            .trim();
    }
    isBreakingSignatureChange(change) {
        const description = change.description?.toLowerCase() ?? '';
        // Return type changes are breaking
        if (description.includes('return type')) {
            return true;
        }
        // Required parameter additions are breaking
        if (description.includes('required param')) {
            return true;
        }
        // Parameter removal is breaking
        if (description.includes('parameter count') && this.hasFewerParams(change)) {
            return true;
        }
        return false;
    }
    hasFewerParams(change) {
        // Extract param counts from description
        const match = change.description?.match(/spec has (\d+), code has (\d+)/);
        if (match) {
            const specCount = parseInt(match[1], 10);
            const codeCount = parseInt(match[2], 10);
            return codeCount < specCount;
        }
        return false;
    }
    getBreakingChangeReason(change) {
        const description = change.description ?? '';
        if (description.includes('required param')) {
            return 'Breaking: New required parameter added';
        }
        if (description.includes('return type') || description.includes('parameter count')) {
            return `Breaking: ${description}`;
        }
        return 'Breaking signature change detected';
    }
    classifyApiRouteChange(change) {
        const specPath = this.extractPath(change.specValue);
        const codePath = this.extractPath(change.codeValue);
        // Version change (v1 -> v2) is major
        if (this.isVersionChange(specPath, codePath)) {
            return {
                severity: 'major',
                reason: `API version changed: ${specPath} → ${codePath}`,
                confidence: 'high',
            };
        }
        // Path structure change is major
        if (this.isPathStructureChange(specPath, codePath)) {
            return {
                severity: 'major',
                reason: `API path structure changed: ${specPath} → ${codePath}`,
                confidence: 'medium',
            };
        }
        // Param name change is minor
        return {
            severity: 'minor',
            reason: `API route modified: ${change.description ?? 'path changed'}`,
            confidence: 'medium',
        };
    }
    classifyFunctionChange(change) {
        const description = change.description?.toLowerCase() ?? '';
        // Parameter type changes are minor (TypeScript will catch issues)
        if (description.includes('parameter') && !description.includes('count')) {
            return {
                severity: 'minor',
                reason: 'Parameter type or name changed',
                confidence: 'medium',
            };
        }
        // Optional parameter additions are minor
        if (description.includes('optional')) {
            return {
                severity: 'minor',
                reason: 'Optional parameter added',
                confidence: 'high',
            };
        }
        return {
            severity: this.config.conservative ? 'minor' : 'trivial',
            reason: 'Function signature modified',
            confidence: 'low',
        };
    }
    extractPath(value) {
        // Extract path from "METHOD /path" format
        const match = value.match(/(?:GET|POST|PUT|DELETE|PATCH)\s+(\S+)/i);
        return match ? match[1] : value;
    }
    isVersionChange(specPath, codePath) {
        const versionPattern = /\/v(\d+)\//;
        const specVersion = specPath.match(versionPattern);
        const codeVersion = codePath.match(versionPattern);
        // New version added where none existed
        if (!specVersion && codeVersion) {
            return true;
        }
        // Both have versions - check if different
        return specVersion !== null && codeVersion !== null && specVersion[1] !== codeVersion[1];
    }
    isPathStructureChange(specPath, codePath) {
        // Normalize paths for comparison
        const specParts = specPath.split('/').filter(Boolean);
        const codeParts = codePath.split('/').filter(Boolean);
        // Different segment count (excluding params)
        const specSegments = specParts.filter(p => !p.startsWith(':'));
        const codeSegments = codeParts.filter(p => !p.startsWith(':'));
        return specSegments.length !== codeSegments.length;
    }
    /**
     * Map severity to recommended action.
     */
    getRecommendation(severity) {
        const actionMap = {
            trivial: 'auto-update',
            minor: 'review-required',
            major: 'notify',
            breaking: 'alert',
        };
        return actionMap[severity];
    }
}
//# sourceMappingURL=severity-classifier.js.map