// engine/detectors/css-framework-detector.ts — CSS framework detection (SPEC-017a)
// Detects CSS frameworks from package.json dependencies, config files, and import signals.
import { readFile } from 'node:fs/promises';
import { join } from 'node:path';
// === Framework signal registry ===
const FRAMEWORK_SIGNALS = {
    tailwind: {
        packageNames: ['tailwindcss'],
        configFiles: ['tailwind.config.ts', 'tailwind.config.js', 'tailwind.config.cjs'],
        importPatterns: [/@tailwind\s+(base|components|utilities)/, /tailwindcss/],
    },
    bootstrap: {
        packageNames: ['bootstrap'],
        configFiles: [],
        importPatterns: [/bootstrap\/dist\/css/, /bootstrap\.min\.css/, /from ['"]bootstrap['"]/],
    },
    'css-modules': {
        packageNames: [],
        configFiles: [],
        importPatterns: [/\.module\.(css|scss|sass)['"]/, /styles from ['"]/],
    },
    'styled-components': {
        packageNames: ['styled-components'],
        configFiles: [],
        importPatterns: [/from ['"]styled-components['"]/, /styled\.\w+`/],
    },
    sass: {
        packageNames: ['sass', 'node-sass'],
        configFiles: ['.sassrc', '.sassrc.js', '.sassrc.json'],
        importPatterns: [/\.(scss|sass)['"]/],
    },
    'material-ui': {
        packageNames: ['@mui/material', '@material-ui/core'],
        configFiles: [],
        importPatterns: [/from ['"]@mui\/material['"]/, /from ['"]@material-ui\/core['"]/],
    },
    'chakra-ui': {
        packageNames: ['@chakra-ui/react'],
        configFiles: [],
        importPatterns: [/from ['"]@chakra-ui\/react['"]/, /ChakraProvider/],
    },
    'shadcn-ui': {
        packageNames: [],
        configFiles: ['components.json'],
        importPatterns: [/from ['"]@\/components\/ui\//, /\bcn\(/],
    },
    'ant-design': {
        packageNames: ['antd', '@ant-design/icons'],
        configFiles: [],
        importPatterns: [/from ['"]antd['"]/, /from ['"]@ant-design\//],
    },
    'css-pure': {
        packageNames: [],
        configFiles: [],
        importPatterns: [/import ['"]\.\/.*\.css['"]/, /import ['"]\.\.\/.*\.css['"]/],
    },
    'flutter-styles': {
        packageNames: [],
        configFiles: ['pubspec.yaml'],
        importPatterns: [/package:flutter\/material\.dart/, /ThemeData/, /ColorScheme/],
    },
    'react-native-styles': {
        packageNames: ['react-native', 'expo'],
        configFiles: [],
        importPatterns: [/from ['"]react-native['"]/, /StyleSheet\.create/],
    },
};
// === Public API ===
/**
 * Detects the primary CSS framework used in a project.
 * Reads package.json, config files, and import patterns.
 */
export async function detectCSSFramework(projectPath) {
    const scores = {};
    const signals = {};
    // Initialize — all framework keys are guaranteed to have a value after this loop
    for (const fw of Object.keys(FRAMEWORK_SIGNALS)) {
        scores[fw] = 0;
        signals[fw] = [];
    }
    // Check package.json dependencies
    await checkPackageJson(projectPath, scores, signals);
    // Check config files
    await checkConfigFiles(projectPath, scores, signals);
    return buildDetectionResult(scores, signals);
}
// === Internal helpers ===
/** Increment a pre-initialized score entry (avoids ?? branch in noUncheckedIndexedAccess). */
function addScore(scores, fw, delta) {
    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
    Object.assign(scores, { [fw]: scores[fw] + delta });
}
async function checkPackageJson(projectPath, scores, signals) {
    try {
        const pkgPath = join(projectPath, 'package.json');
        const content = await readFile(pkgPath, 'utf-8');
        const pkg = JSON.parse(content);
        const allDeps = {
            ...pkg.dependencies,
            ...pkg.devDependencies,
        };
        for (const fw of Object.keys(FRAMEWORK_SIGNALS)) {
            const frameworkSignals = FRAMEWORK_SIGNALS[fw];
            for (const pkgName of frameworkSignals.packageNames) {
                if (pkgName in allDeps) {
                    addScore(scores, fw, 3); // package.json is high confidence
                    /* v8 ignore next 1 */ // signals[fw] is always initialized in detectCSSFramework
                    signals[fw]?.push(`package.json: ${pkgName}`);
                }
            }
        }
    }
    catch {
        // package.json not found or not parseable — continue
    }
}
async function checkConfigFiles(projectPath, scores, signals) {
    for (const fw of Object.keys(FRAMEWORK_SIGNALS)) {
        const frameworkSignals = FRAMEWORK_SIGNALS[fw];
        for (const configFile of frameworkSignals.configFiles) {
            const exists = await fileExists(join(projectPath, configFile));
            if (exists) {
                addScore(scores, fw, 2); // config file is medium-high confidence
                /* v8 ignore next 1 */ // signals[fw] is always initialized in detectCSSFramework
                signals[fw]?.push(`config: ${configFile}`);
            }
        }
    }
}
async function fileExists(filePath) {
    try {
        await readFile(filePath, 'utf-8');
        return true;
    }
    catch {
        return false;
    }
}
/** Map a numeric score to a confidence label. All real detections yield score ≥ 2. */
function scoreToConfidence(score) {
    if (score >= 3) {
        return 'high';
    }
    /* v8 ignore start */ // score < 2 is unreachable: minimum detection score is 2 (config file)
    if (score >= 2) {
        return 'medium';
    }
    return 'low';
    /* v8 ignore stop */
}
/** Read a pre-initialized score without ?? (avoids uncovered binary-expr branches). */
function getScore(scores, fw) {
    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
    return scores[fw];
}
function buildDetectionResult(scores, signals) {
    // Sort by score descending — scores are always initialized for all frameworks
    const sorted = Object.keys(scores)
        .filter((fw) => getScore(scores, fw) > 0)
        .sort((a, b) => getScore(scores, b) - getScore(scores, a));
    if (sorted.length === 0) {
        return {
            framework: null,
            confidence: 'low',
            signals: [],
            multipleDetected: [],
        };
    }
    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
    const primary = sorted[0];
    const primaryScore = getScore(scores, primary);
    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
    const primarySignals = signals[primary];
    const multipleDetected = sorted.slice(1).filter((fw) => getScore(scores, fw) >= 2);
    const confidence = scoreToConfidence(primaryScore);
    const result = {
        framework: primary,
        confidence,
        signals: primarySignals,
        multipleDetected: multipleDetected.map((fw) => fw),
    };
    if (multipleDetected.length > 0) {
        result.warning = `Multiple CSS frameworks detected: ${[primary, ...multipleDetected].join(', ')}. Using primary: ${primary}. Consider consolidating to a single framework.`;
    }
    return result;
}
//# sourceMappingURL=css-framework-detector.js.map