/**
 * Cross-Cutting Feature Detector
 *
 * Detects when a feature spans multiple projects based on keywords,
 * tech stack mentions, and component references.
 *
 * @module utils/cross-cutting-detector
 * @since v0.33.0
 */
import { consoleLogger } from './logger.js';
/**
 * Cross-cutting detection keywords and mappings
 */
const CROSS_CUTTING_PATTERNS = {
    // Frontend indicators
    frontend: ['frontend', 'ui', 'react', 'vue', 'angular', 'next.js', 'nuxt', 'svelte', 'client-side', 'browser'],
    // Backend indicators
    backend: ['backend', 'api', 'server', 'node', 'express', 'fastify', 'django', 'flask', 'rails', 'spring', 'graphql', 'rest api'],
    // Infrastructure indicators
    infrastructure: ['infrastructure', 'infra', 'devops', 'ci/cd', 'pipeline', 'kubernetes', 'k8s', 'docker', 'terraform', 'aws', 'azure', 'gcp'],
    // Database indicators
    database: ['database', 'db', 'postgres', 'mysql', 'mongodb', 'redis', 'elasticsearch', 'migration', 'schema'],
    // Security indicators
    security: ['security', 'auth', 'oauth', 'authentication', 'authorization', 'rbac', 'permissions', 'jwt', 'sso'],
    // Mobile indicators
    mobile: ['mobile', 'ios', 'android', 'react native', 'flutter', 'app store', 'play store'],
    // Shared/common indicators
    shared: ['shared', 'common', 'library', 'sdk', 'package', 'module', 'types', 'models']
};
/**
 * Explicit cross-cutting phrases
 */
const EXPLICIT_CROSS_CUTTING = [
    'across projects',
    'multiple repos',
    'cross-project',
    'cross-team',
    'frontend and backend',
    'end-to-end',
    'full-stack',
    'fullstack',
    'from ui to api',
    'from client to server',
    'all services',
    'all teams',
    'affects multiple',
    'impacts all'
];
/**
 * Cross-Cutting Detector
 */
export class CrossCuttingDetector {
    constructor(options = {}) {
        this.customMappings = {};
        this.logger = options.logger ?? consoleLogger;
        this.customMappings = options.customMappings ?? {};
    }
    /**
     * Detect if a description indicates cross-cutting concerns
     */
    detect(description) {
        const normalized = description.toLowerCase();
        const detectedPatterns = [];
        const suggestedProjects = new Set();
        // 1. Check explicit cross-cutting phrases (high confidence)
        for (const phrase of EXPLICIT_CROSS_CUTTING) {
            if (normalized.includes(phrase)) {
                detectedPatterns.push({
                    type: 'explicit',
                    matched: phrase
                });
            }
        }
        // 2. Check keyword patterns
        const allPatterns = { ...CROSS_CUTTING_PATTERNS, ...this.customMappings };
        for (const [project, keywords] of Object.entries(allPatterns)) {
            for (const keyword of keywords) {
                // Use word boundary matching for more accuracy
                const regex = new RegExp(`\\b${this.escapeRegex(keyword)}\\b`, 'i');
                if (regex.test(description)) {
                    detectedPatterns.push({
                        type: 'keyword',
                        matched: keyword,
                        suggestedProject: project
                    });
                    suggestedProjects.add(project);
                }
            }
        }
        // 3. Determine if cross-cutting
        const uniqueProjects = [...suggestedProjects];
        const isCrossCutting = uniqueProjects.length >= 2 || detectedPatterns.some(p => p.type === 'explicit');
        // 4. Calculate confidence
        let confidence = 'low';
        if (detectedPatterns.some(p => p.type === 'explicit')) {
            confidence = 'high';
        }
        else if (uniqueProjects.length >= 3) {
            confidence = 'high';
        }
        else if (uniqueProjects.length === 2) {
            // Check if multiple keywords matched per project
            const projectKeywordCounts = new Map();
            for (const pattern of detectedPatterns) {
                if (pattern.suggestedProject) {
                    projectKeywordCounts.set(pattern.suggestedProject, (projectKeywordCounts.get(pattern.suggestedProject) || 0) + 1);
                }
            }
            const minMatches = Math.min(...projectKeywordCounts.values());
            confidence = minMatches >= 2 ? 'high' : 'medium';
        }
        // 5. Generate reason
        let reason;
        if (isCrossCutting) {
            if (detectedPatterns.some(p => p.type === 'explicit')) {
                const explicit = detectedPatterns.find(p => p.type === 'explicit');
                reason = `Explicit cross-cutting phrase detected: "${explicit?.matched}"`;
            }
            else {
                reason = `Multiple project domains detected: ${uniqueProjects.join(', ')}`;
            }
        }
        return {
            isCrossCutting,
            confidence,
            suggestedProjects: uniqueProjects,
            detectedPatterns,
            reason
        };
    }
    /**
     * Add custom project mappings
     */
    addCustomMapping(project, keywords) {
        this.customMappings[project] = [
            ...(this.customMappings[project] || []),
            ...keywords
        ];
    }
    /**
     * Load custom mappings from config
     */
    loadMappingsFromConfig(projectMappings) {
        // Extract project IDs as potential mapping targets
        for (const projectId of Object.keys(projectMappings)) {
            // Add the project ID itself as a keyword
            if (!this.customMappings[projectId]) {
                this.customMappings[projectId] = [projectId];
            }
        }
    }
    /**
     * Escape regex special characters
     */
    escapeRegex(str) {
        return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
    }
}
/**
 * Convenience function for one-off detection
 */
export function detectCrossCutting(description, options) {
    const detector = new CrossCuttingDetector(options);
    return detector.detect(description);
}
/**
 * Get suggested project for a single-project feature
 */
export function suggestSingleProject(description) {
    const result = detectCrossCutting(description);
    if (result.isCrossCutting) {
        return null; // Ambiguous - needs user selection
    }
    if (result.suggestedProjects.length === 1) {
        return result.suggestedProjects[0];
    }
    return null; // No clear suggestion
}
//# sourceMappingURL=cross-cutting-detector.js.map