import { writeFile } from "node:fs/promises";
import { join } from "node:path";
import { getCodeIndex } from "./index-tools.js";
import { analyzeComplexity } from "./complexity-tools.js";
import { findDeadCode } from "./symbol-tools.js";
import { detectCommunities } from "./community-tools.js";
import { analyzeHotspots } from "./hotspot-tools.js";
import { getCumulativeSavings } from "../storage/usage-tracker.js";
export async function generateReport(repo) {
    const index = await getCodeIndex(repo);
    if (!index)
        throw new Error(`Repository "${repo}" not found.`);
    const [complexity, deadCode, communities, hotspots] = await Promise.allSettled([
        analyzeComplexity(repo, { top_n: 10 }),
        findDeadCode(repo, {}),
        detectCommunities(repo),
        analyzeHotspots(repo, {}),
    ]);
    const html = buildHtml(repo, index, {
        complexity: complexity.status === "fulfilled" ? complexity.value : null,
        deadCode: deadCode.status === "fulfilled" ? deadCode.value : null,
        communities: communities.status === "fulfilled" ? communities.value : null,
        hotspots: hotspots.status === "fulfilled" ? hotspots.value : null,
        savings: getCumulativeSavings(),
    });
    const outPath = join(index.root, "codesift-report.html");
    await writeFile(outPath, html, "utf-8");
    return { path: outPath, sections: 6 };
}
function buildHtml(repo, index, data) {
    const langs = Object.entries(index.files.reduce((acc, f) => {
        acc[f.language] = (acc[f.language] ?? 0) + 1;
        return acc;
    }, {})).sort((a, b) => b[1] - a[1]);
    const complexityRows = buildComplexityRows(data.complexity);
    const deadCodeSection = buildDeadCodeSection(data.deadCode);
    const hotspotRows = buildHotspotRows(data.hotspots);
    const communitiesSection = buildCommunitiesSection(data.communities);
    const reactSection = buildReactSection(index);
    return `<!DOCTYPE html>
<html lang="en"><head><meta charset="utf-8"><title>CodeSift Report \u2014 ${esc(repo)}</title>
<style>
  * { box-sizing: border-box; margin: 0; padding: 0; }
  body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif; max-width: 960px; margin: 40px auto; padding: 0 24px; color: #1e293b; background: #f8fafc; line-height: 1.6; }
  h1 { font-size: 28px; border-bottom: 3px solid #6366f1; padding-bottom: 12px; margin-bottom: 8px; }
  h2 { color: #6366f1; margin-top: 36px; margin-bottom: 12px; font-size: 20px; }
  p { margin: 8px 0; color: #475569; }
  table { border-collapse: collapse; width: 100%; margin: 12px 0; font-size: 14px; }
  th, td { border: 1px solid #e2e8f0; padding: 8px 12px; text-align: left; }
  th { background: #6366f1; color: white; font-weight: 600; }
  tr:nth-child(even) { background: #f1f5f9; }
  .metrics { display: flex; gap: 8px; flex-wrap: wrap; margin: 16px 0; }
  .metric { background: #6366f1; color: white; padding: 8px 16px; border-radius: 8px; font-size: 14px; }
  .metric b { font-size: 20px; display: block; }
  .warn { color: #dc2626; font-weight: 600; }
  .ok { color: #16a34a; }
  .empty { color: #94a3b8; font-style: italic; }
  footer { margin-top: 48px; padding-top: 16px; border-top: 1px solid #e2e8f0; color: #94a3b8; font-size: 12px; }
  footer a { color: #6366f1; }
</style></head><body>
<h1>CodeSift Report</h1>
<p><strong>${esc(repo)}</strong> \u2014 generated ${new Date().toISOString().slice(0, 10)}</p>

<div class="metrics">
  <div class="metric"><b>${index.file_count.toLocaleString()}</b>files</div>
  <div class="metric"><b>${index.symbol_count.toLocaleString()}</b>symbols</div>
  <div class="metric"><b>${langs.length}</b>languages</div>
  ${data.savings > 0 ? `<div class="metric"><b>${data.savings.toLocaleString()}</b>tokens saved</div>` : ""}
</div>

<h2>Languages</h2>
<table><tr><th>Language</th><th>Files</th></tr>
${langs.map(([l, c]) => `<tr><td>${esc(l)}</td><td>${c}</td></tr>`).join("\n")}
</table>

<h2>Top Complex Functions</h2>
${complexityRows}

<h2>Dead Code Candidates</h2>
${deadCodeSection}

<h2>Hotspots (Churn \u00d7 Complexity)</h2>
${hotspotRows}

<h2>Architecture (Communities)</h2>
${communitiesSection}

${reactSection}

<footer>Generated by <a href="https://github.com/greglas75/codesift">CodeSift</a> \u2014 Token-efficient code intelligence for AI agents</footer>
</body></html>`;
}
/**
 * Build the React section of the report — only emitted when the index has
 * `kind: "component"` symbols. Renders component count, hook count, top
 * components by source size, and most-used hooks. Returns empty string for
 * non-React projects.
 */
function buildReactSection(index) {
    const components = index.symbols.filter((s) => s.kind === "component");
    const hooks = index.symbols.filter((s) => s.kind === "hook");
    if (components.length === 0 && hooks.length === 0)
        return "";
    // Top 5 components by source length (complexity proxy)
    const topComponents = [...components]
        .sort((a, b) => (b.source?.length ?? 0) - (a.source?.length ?? 0))
        .slice(0, 5);
    // Hook usage frequency across components
    const hookCounts = new Map();
    for (const c of components) {
        const matches = c.source?.matchAll(/\b(use[A-Z]\w*)\s*\(/g);
        if (!matches)
            continue;
        for (const m of matches) {
            hookCounts.set(m[1], (hookCounts.get(m[1]) ?? 0) + 1);
        }
    }
    const topHooks = [...hookCounts.entries()]
        .sort((a, b) => b[1] - a[1])
        .slice(0, 8);
    return `<h2>React</h2>
<div class="metrics">
  <div class="metric"><b>${components.length}</b>components</div>
  <div class="metric"><b>${hooks.length}</b>custom hooks</div>
  <div class="metric"><b>${hookCounts.size}</b>hooks used</div>
</div>
${topComponents.length > 0 ? `<h2>Top Components by Size</h2>
<table><tr><th>Component</th><th>File</th><th>Lines</th></tr>
${topComponents.map((c) => `<tr><td>${esc(c.name)}</td><td>${esc(c.file)}</td><td>${(c.end_line ?? 0) - (c.start_line ?? 0)}</td></tr>`).join("\n")}
</table>` : ""}
${topHooks.length > 0 ? `<h2>Most-used Hooks</h2>
<table><tr><th>Hook</th><th>Usages</th></tr>
${topHooks.map(([name, count]) => `<tr><td>${esc(name)}</td><td>${count}</td></tr>`).join("\n")}
</table>` : ""}
`;
}
function buildComplexityRows(complexity) {
    if (complexity !== null &&
        typeof complexity === "object" &&
        "functions" in complexity &&
        Array.isArray(complexity["functions"])) {
        const fns = complexity.functions;
        if (fns.length > 0) {
            return `<table><tr><th>Function</th><th>File</th><th>Complexity</th><th>Lines</th></tr>
${fns.slice(0, 10).map((c) => {
                const fn = c;
                return `<tr><td>${esc(fn.name)}</td><td>${esc(fn.file)}</td><td class="${fn.cyclomatic > 10 ? "warn" : "ok"}">${fn.cyclomatic}</td><td>${fn.lines}</td></tr>`;
            }).join("\n")}
</table>`;
        }
    }
    return `<p class="empty">Analysis not available</p>`;
}
function buildDeadCodeSection(deadCode) {
    if (deadCode !== null &&
        typeof deadCode === "object" &&
        "candidates" in deadCode &&
        Array.isArray(deadCode["candidates"])) {
        const candidates = deadCode.candidates;
        if (candidates.length > 0) {
            return `<p>${candidates.length} unused exports found</p>
<table><tr><th>Symbol</th><th>File</th><th>Kind</th></tr>
${candidates.slice(0, 15).map((d) => {
                const dc = d;
                return `<tr><td>${esc(dc.name)}</td><td>${esc(dc.file)}</td><td>${esc(dc.kind)}</td></tr>`;
            }).join("\n")}
</table>`;
        }
    }
    return `<p class="empty">No dead code found (or analysis not available)</p>`;
}
function buildHotspotRows(hotspots) {
    if (hotspots !== null &&
        typeof hotspots === "object" &&
        "hotspots" in hotspots &&
        Array.isArray(hotspots["hotspots"])) {
        const spots = hotspots.hotspots;
        if (spots.length > 0) {
            return `<table><tr><th>File</th><th>Score</th><th>Changes</th></tr>
${spots.slice(0, 10).map((h) => {
                const hs = h;
                return `<tr><td>${esc(hs.file)}</td><td class="${hs.hotspot_score > 100 ? "warn" : "ok"}">${hs.hotspot_score}</td><td>${hs.change_count}</td></tr>`;
            }).join("\n")}
</table>`;
        }
    }
    return `<p class="empty">Hotspot analysis not available (requires git history)</p>`;
}
function buildCommunitiesSection(communities) {
    if (communities !== null &&
        typeof communities === "object" &&
        "communities" in communities &&
        Array.isArray(communities["communities"])) {
        const result = communities;
        if (result.communities.length > 0) {
            return `<p>${result.communities.length} modules detected (modularity: ${result.modularity})</p>
<table><tr><th>Module</th><th>Files</th><th>Symbols</th><th>Cohesion</th></tr>
${result.communities.slice(0, 15).map((c) => {
                const cm = c;
                return `<tr><td>${esc(cm.name)}</td><td>${cm.files.length}</td><td>${cm.symbol_count}</td><td>${(cm.cohesion * 100).toFixed(0)}%</td></tr>`;
            }).join("\n")}
</table>`;
        }
    }
    return `<p class="empty">Community detection not available</p>`;
}
function esc(s) {
    return s
        .replace(/&/g, "&amp;")
        .replace(/</g, "&lt;")
        .replace(/>/g, "&gt;")
        .replace(/"/g, "&quot;");
}
//# sourceMappingURL=report-tools.js.map