// overview-generator.ts — generates a project overview spec (spec.md) with mermaid diagrams
// ---------------------------------------------------------------------------
// Public API
// ---------------------------------------------------------------------------
export function generateProjectOverview(modules, moduleResults, crossModuleAnalysis, healthScore) {
    const generatedAt = new Date().toISOString();
    const moduleTable = buildModuleTable(modules, moduleResults);
    const archMap = buildArchMap(modules, crossModuleAnalysis);
    const depGraph = buildDepGraph(crossModuleAnalysis);
    const healthTable = buildHealthTable(healthScore);
    const antipatternSection = buildAntipatternSection(crossModuleAnalysis);
    const implOrder = buildImplementationOrder(modules, crossModuleAnalysis);
    return [
        buildHeader(modules.length, healthScore, generatedAt),
        moduleTable,
        archMap,
        depGraph,
        healthTable,
        antipatternSection,
        implOrder,
    ].join('\n\n');
}
// ---------------------------------------------------------------------------
// Header
// ---------------------------------------------------------------------------
function buildHeader(count, healthScore, generatedAt) {
    return [
        '# Project Overview — Automated Scan',
        '',
        `> **Type:** project | **Generated:** ${generatedAt}`,
        `> **Health Score:** ${healthScore.score}/100 (Grade ${healthScore.grade})`,
        '',
        `## Modules Discovered (${count})`,
    ].join('\n');
}
// ---------------------------------------------------------------------------
// Module table
// ---------------------------------------------------------------------------
function buildModuleTable(modules, moduleResults) {
    const resultMap = new Map(moduleResults.map((r) => [r.module.name, r]));
    const rows = modules.map((m) => {
        const result = resultMap.get(m.name);
        const ratio = resolveTestRatio(result);
        return `| ${m.name} | ${m.language} | ${m.estimatedFiles} | ${ratio} |`;
    });
    return [
        '| Module | Language | Files | Test Ratio |',
        '|--------|----------|-------|------------|',
        ...rows,
    ].join('\n');
}
function resolveTestRatio(result) {
    if (result?.status !== 'success') {
        return 'N/A';
    }
    const ratio = result.analysis.testCoverage.testToSourceRatio;
    return `${(ratio * 100).toFixed(0)}%`;
}
// ---------------------------------------------------------------------------
// Architecture map (TD graph — nodes + cross-module edges)
// ---------------------------------------------------------------------------
function buildArchMap(modules, crossModuleAnalysis) {
    const nodes = modules
        .map((m) => {
        const id = sanitizeMermaidId(m.name);
        return `  ${id}[${m.name}]`;
    })
        .join('\n');
    const edges = crossModuleAnalysis.dependencies
        .map((d) => {
        const from = sanitizeMermaidId(d.from);
        const to = sanitizeMermaidId(d.to);
        return `  ${from} --> ${to}`;
    })
        .join('\n');
    const body = [nodes, edges].filter(Boolean).join('\n');
    return ['## Architecture Map', '', '```mermaid', 'graph TD', body, '```'].join('\n');
}
// ---------------------------------------------------------------------------
// Cross-module dependency graph (LR graph with type labels)
// ---------------------------------------------------------------------------
function buildDepGraph(crossModuleAnalysis) {
    if (crossModuleAnalysis.dependencies.length === 0) {
        return '## Cross-module Dependencies\n\n_No cross-module dependencies detected._';
    }
    const edges = crossModuleAnalysis.dependencies
        .map((d) => {
        const from = sanitizeMermaidId(d.from);
        const to = sanitizeMermaidId(d.to);
        return `  ${from} -->|${d.type}| ${to}`;
    })
        .join('\n');
    return ['## Cross-module Dependencies', '', '```mermaid', 'graph LR', edges, '```'].join('\n');
}
// ---------------------------------------------------------------------------
// Health score table
// ---------------------------------------------------------------------------
function buildHealthTable(healthScore) {
    const { breakdown, score, grade } = healthScore;
    const rows = [
        `| Test Coverage | ${breakdown.testCoverage}/100 |`,
        `| Tech Debt | ${breakdown.techDebt}/100 |`,
        `| Arch Consistency | ${breakdown.archConsistency}/100 |`,
        `| Dep Health | ${breakdown.depHealth}/100 |`,
        `| **Overall** | **${score}/100 (${grade})** |`,
    ];
    return [
        '## Health Score Breakdown',
        '',
        '| Dimension | Score |',
        '|-----------|-------|',
        ...rows,
    ].join('\n');
}
// ---------------------------------------------------------------------------
// Antipattern section
// ---------------------------------------------------------------------------
const SEVERITY_ICON = {
    critical: '🔴',
    high: '🟠',
    medium: '🟡',
    low: '🔵',
};
const SEVERITY_ORDER = {
    critical: 0,
    high: 1,
    medium: 2,
    low: 3,
};
function buildAntipatternSection(crossModuleAnalysis) {
    const { antipatterns } = crossModuleAnalysis;
    const count = antipatterns.length;
    const header = `## Antipatterns Found (${count})`;
    if (count === 0) {
        return `${header}\n\n_No antipatterns detected._`;
    }
    const sorted = [...antipatterns].sort((a, b) => (SEVERITY_ORDER[a.severity] ?? 9) - (SEVERITY_ORDER[b.severity] ?? 9));
    const blocks = sorted.map((ap) => {
        const icon = SEVERITY_ICON[ap.severity] ?? '⚪';
        return [
            `### ${icon} ${ap.description}`,
            `- **Modules:** ${ap.modules.join(', ')}`,
            `- **Suggestion:** ${ap.suggestion}`,
        ].join('\n');
    });
    return [header, '', ...blocks].join('\n\n');
}
// ---------------------------------------------------------------------------
// Implementation order (topological sort — Kahn's algorithm)
// ---------------------------------------------------------------------------
function buildImplementationOrder(modules, crossModuleAnalysis) {
    const { sorted, cycleNote } = topoSort(modules, crossModuleAnalysis);
    const header = '## Suggested Implementation Order';
    const lines = sorted.map((entry, i) => {
        const idx = i + 1;
        const depSuffix = entry.deps.length > 0 ? ` — depends on ${entry.deps.join(', ')}` : ' — no dependencies';
        return `${idx}. ${entry.name}${depSuffix}`;
    });
    const cycleBlock = cycleNote ? `\n\n> **Note:** ${cycleNote}` : '';
    return [header, '', ...lines, cycleBlock].join('\n').trimEnd();
}
function topoSort(modules, crossModuleAnalysis) {
    const moduleNames = modules.map((m) => m.name);
    const moduleSet = new Set(moduleNames);
    const inDegree = new Map(moduleNames.map((n) => [n, 0]));
    const dependsOn = new Map(moduleNames.map((n) => [n, []]));
    const downstream = new Map(moduleNames.map((n) => [n, []]));
    for (const dep of crossModuleAnalysis.dependencies) {
        if (!moduleSet.has(dep.from) || !moduleSet.has(dep.to)) {
            continue;
        }
        inDegree.set(dep.from, (inDegree.get(dep.from) ?? 0) + 1);
        dependsOn.get(dep.from)?.push(dep.to);
        downstream.get(dep.to)?.push(dep.from);
    }
    const queue = [];
    for (const [name, degree] of inDegree) {
        if (degree === 0) {
            queue.push(name);
        }
    }
    const sorted = [];
    const visited = new Set();
    while (queue.length > 0) {
        const current = queue.shift();
        if (current === undefined) {
            break;
        }
        visited.add(current);
        sorted.push({ name: current, deps: dependsOn.get(current) ?? [] });
        for (const next of downstream.get(current) ?? []) {
            if (visited.has(next)) {
                continue;
            }
            const newDegree = (inDegree.get(next) ?? 1) - 1;
            inDegree.set(next, newDegree);
            if (newDegree === 0) {
                queue.push(next);
            }
        }
    }
    const remaining = moduleNames.filter((n) => !visited.has(n));
    let cycleNote = '';
    if (remaining.length > 0) {
        for (const name of remaining) {
            sorted.push({ name, deps: dependsOn.get(name) ?? [] });
        }
        cycleNote = `Circular dependency detected among: ${remaining.join(', ')}. Order within the cycle is approximate.`;
    }
    return { sorted, cycleNote };
}
// ---------------------------------------------------------------------------
// Utilities
// ---------------------------------------------------------------------------
function sanitizeMermaidId(name) {
    return name.replace(/[^a-zA-Z0-9_]/g, '_');
}
//# sourceMappingURL=overview-generator.js.map