// engine/detectors/mfe-detector.ts — Micro-frontend and signals detection (SPEC-017 tech-debt)
// Detects Islands Architecture, Module Federation, Single-SPA, Nx MFE, Reactive Signals.
import { readFile } from 'node:fs/promises';
import { join } from 'node:path';
import { glob } from 'glob';
const IGNORE_DIRS = ['node_modules/**', 'dist/**', 'build/**', '.git/**'];
/**
 * SPEC-017 tech-debt: Detect micro-frontend patterns and reactive signals in a project.
 * Covers Islands Architecture, SolidStart, TanStack Start, Module Federation,
 * Single-SPA, Nx MFE, and Reactive Signals (Angular/Preact/Solid/Vue).
 */
export async function detectMfe(projectPath) {
    const allDeps = await collectAllDeps(projectPath);
    const islands = await detectIslands(projectPath, allDeps);
    const solidStart = detectSolidStart(allDeps);
    const tanstackStart = detectTanstackStart(allDeps);
    const moduleFederation = await detectModuleFederation(projectPath, allDeps);
    const singleSpa = detectSingleSpa(allDeps);
    const nxMfe = await detectNxMfe(projectPath);
    const signals = detectSignals(allDeps);
    const result = {};
    if (islands.framework !== undefined) {
        result.islandsFramework = islands.framework;
        result.hydration = 'islands';
    }
    if (solidStart) {
        result.solidStart = true;
    }
    if (tanstackStart) {
        result.tanstackStart = true;
    }
    if (moduleFederation !== undefined) {
        result.moduleFederation = moduleFederation;
    }
    if (singleSpa) {
        result.singleSpa = true;
    }
    if (nxMfe) {
        result.nxMfe = true;
    }
    if (signals.length > 0) {
        result.signals = signals;
    }
    return result;
}
// === Internal helpers ===
async function collectAllDeps(projectPath) {
    const deps = new Set();
    try {
        const content = await readFile(join(projectPath, 'package.json'), 'utf-8');
        const pkg = JSON.parse(content);
        for (const dep of Object.keys(pkg.dependencies ?? {})) {
            deps.add(dep);
        }
        for (const dep of Object.keys(pkg.devDependencies ?? {})) {
            deps.add(dep);
        }
    }
    catch {
        // No package.json — deps remain empty
    }
    return deps;
}
async function detectIslands(projectPath, deps) {
    // Astro: astro.config.mjs / .ts / .js
    const hasAstroConfig = (await fileExists(join(projectPath, 'astro.config.mjs'))) ||
        (await fileExists(join(projectPath, 'astro.config.ts'))) ||
        (await fileExists(join(projectPath, 'astro.config.js')));
    if (hasAstroConfig || deps.has('astro')) {
        return { framework: 'astro' };
    }
    // Fresh (Deno): fresh.config.ts
    if (await fileExists(join(projectPath, 'fresh.config.ts'))) {
        return { framework: 'fresh' };
    }
    return { framework: undefined };
}
function detectSolidStart(deps) {
    return deps.has('solid-js') && deps.has('@solidjs/start');
}
function detectTanstackStart(deps) {
    return deps.has('@tanstack/router') && deps.has('@tanstack/start');
}
async function detectModuleFederation(projectPath, deps) {
    // Vite plugin: @module-federation/vite
    if (deps.has('@module-federation/vite')) {
        return { pattern: 'module-federation', tool: 'vite' };
    }
    // Webpack: ModuleFederationPlugin in webpack.config.js or webpack.config.ts
    const webpackContent = await readWebpackConfig(projectPath);
    if (webpackContent?.includes('ModuleFederationPlugin')) {
        return { pattern: 'module-federation', tool: 'webpack' };
    }
    return undefined;
}
async function readWebpackConfig(projectPath) {
    for (const filename of ['webpack.config.js', 'webpack.config.ts', 'webpack.config.cjs']) {
        try {
            return await readFile(join(projectPath, filename), 'utf-8');
        }
        catch {
            // Try next
        }
    }
    return null;
}
function detectSingleSpa(deps) {
    return deps.has('single-spa');
}
async function detectNxMfe(projectPath) {
    try {
        const projectJsonFiles = await glob('**/project.json', {
            cwd: projectPath,
            nodir: true,
            ignore: IGNORE_DIRS,
            maxDepth: 5,
        });
        for (const file of projectJsonFiles) {
            const content = await readFile(join(projectPath, file), 'utf-8');
            if (content.includes('@nx/angular:module-federation') ||
                content.includes('@nx/react:module-federation') ||
                content.includes('@nx/angular:module-federation-dev-server') ||
                content.includes('@nx/react:module-federation-dev-server')) {
                return true;
            }
        }
    }
    catch {
        // Glob or read error — skip
    }
    return false;
}
function detectSignals(deps) {
    const detected = [];
    // Angular Signals: @angular/core (v16+ has signals built-in)
    if (deps.has('@angular/core')) {
        detected.push('angular');
    }
    // Preact Signals: @preact/signals-react or @preact/signals
    if (deps.has('@preact/signals-react') || deps.has('@preact/signals')) {
        detected.push('preact');
    }
    // SolidJS Signals: solid-js (createSignal is core)
    if (deps.has('solid-js')) {
        detected.push('solid');
    }
    // Vue Reactivity: vue (ref/reactive are core)
    if (deps.has('vue')) {
        detected.push('vue');
    }
    return detected;
}
async function fileExists(filePath) {
    try {
        await readFile(filePath, 'utf-8');
        return true;
    }
    catch {
        return false;
    }
}
//# sourceMappingURL=mfe-detector.js.map