/**
 * Compact and counts formatters for progressive response shortening.
 * Used by registerShortener() to reduce large tool responses.
 */
import { formatTable } from "./formatters.js";
// ── Generic array-cap budgeting ────────────────────
//
// Composite tools (nest_audit, impact_analysis) can emit 100K+ token
// responses — telemetry showed nest_audit peaks of 110K tokens that the
// downstream cascade could only hard-truncate mid-JSON. This shrinker
// keeps JSON valid: it deep-caps every array, retrying with smaller caps
// until the payload fits the char budget. A no-op for responses already
// under budget.
const ARRAY_CAP_LADDER = [30, 10, 5, 3];
function deepCapArrays(value, cap) {
    if (Array.isArray(value)) {
        const items = value.slice(0, cap).map((v) => deepCapArrays(v, cap));
        if (value.length > cap) {
            items.push(`… ${value.length - cap} more items truncated — narrow with checks=/file_pattern= for full detail`);
        }
        return items;
    }
    if (value && typeof value === "object") {
        const out = {};
        for (const [k, v] of Object.entries(value))
            out[k] = deepCapArrays(v, cap);
        return out;
    }
    return value;
}
/**
 * Cap arrays throughout `value` so its JSON form fits `budgetChars`.
 * Returns the original object untouched when already within budget.
 */
export function capArraysToBudget(value, opts) {
    const budget = opts?.budgetChars ?? 60_000;
    let json;
    try {
        json = JSON.stringify(value) ?? "";
    }
    catch {
        return value; // circular or non-serializable — leave to the caller
    }
    if (json.length <= budget)
        return value;
    let smallest = value;
    for (const cap of ARRAY_CAP_LADDER) {
        smallest = deepCapArrays(value, cap);
        if ((JSON.stringify(smallest) ?? "").length <= budget)
            return smallest;
    }
    return smallest; // best effort at the tightest cap
}
// ── Analyze complexity ─────────────────────────────
const MAX_COMPLEXITY_COMPACT = 25;
export function formatComplexityCompact(raw) {
    const data = raw;
    if (data.functions.length === 0)
        return "(no functions found)";
    const capped = data.functions.slice(0, MAX_COMPLEXITY_COMPACT);
    const rows = capped.map((f) => [
        String(f.cyclomatic_complexity),
        String(f.lines),
        `${f.file}:${f.start_line}`,
        f.name,
    ]);
    return formatTable(["CC", "LINES", "FILE:LINE", "NAME"], rows);
}
export function formatComplexityCounts(raw) {
    const data = raw;
    const s = data.summary;
    return `${s.total_functions} functions, avg_cc=${s.avg_complexity}, max_cc=${s.max_complexity}`;
}
// ── Find clones ────────────────────────────────────
const MAX_CLONES_COMPACT = 20;
function basename(filePath) {
    const parts = filePath.replace(/\\/g, "/").split("/");
    return parts[parts.length - 1] ?? filePath;
}
export function formatClonesCompact(raw) {
    const data = raw;
    if (data.clones.length === 0) {
        return `(no clones found, threshold=${data.threshold}, scanned ${data.scanned_symbols} symbols)`;
    }
    const capped = data.clones.slice(0, MAX_CLONES_COMPACT);
    const rows = capped.map((c) => [
        `${Math.round(c.similarity * 100)}%`,
        String(c.shared_lines),
        `${basename(c.symbol_a.file)} ${c.symbol_a.name}`,
        `${basename(c.symbol_b.file)} ${c.symbol_b.name}`,
    ]);
    return formatTable(["SIM%", "SHARED", "SYMBOL_A", "SYMBOL_B"], rows);
}
export function formatClonesCounts(raw) {
    const data = raw;
    return `${data.clones.length} clone pairs (threshold=${data.threshold}, scanned ${data.scanned_symbols})`;
}
const MAX_CHAIN_COMPACT = 20;
export function formatTraceRouteCompact(raw) {
    const data = raw;
    const parts = [`route: ${data.path}`];
    if (data.handlers.length > 0) {
        parts.push(`handlers (${data.handlers.length}):`);
        for (const h of data.handlers) {
            const sym = h.symbol ? `${h.symbol.kind} ${h.symbol.name}` : "?";
            parts.push(`  ${h.file} ${sym}`);
        }
    }
    if (data.call_chain.length > 0) {
        const capped = data.call_chain.slice(0, MAX_CHAIN_COMPACT);
        parts.push(`call chain (${data.call_chain.length}, showing ${capped.length}):`);
        for (const c of capped) {
            parts.push(`${"  ".repeat(c.depth + 1)}${c.file}:${c.name}`);
        }
        if (data.call_chain.length > MAX_CHAIN_COMPACT) {
            parts.push(`  ... +${data.call_chain.length - MAX_CHAIN_COMPACT} more`);
        }
    }
    if (data.db_calls.length > 0) {
        parts.push(`DB calls (${data.db_calls.length}):`);
        for (const d of data.db_calls.slice(0, 10)) {
            parts.push(`  ${d.file}:${d.line} ${d.operation}`);
        }
    }
    return parts.join("\n");
}
export function formatTraceRouteCounts(raw) {
    const data = raw;
    return `route ${data.path}: ${data.handlers.length} handlers, ${data.call_chain.length} call chain nodes, ${data.db_calls.length} DB calls`;
}
// ── Analyze hotspots ───────────────────────────────
const MAX_HOTSPOTS_COMPACT = 15;
export function formatHotspotsCompact(raw) {
    const data = raw;
    if (data.hotspots.length === 0)
        return `(no hotspots found, period: ${data.period})`;
    const capped = data.hotspots.slice(0, MAX_HOTSPOTS_COMPACT);
    const rows = capped.map((h) => [
        String(h.hotspot_score),
        String(h.commits),
        h.file,
    ]);
    return formatTable(["SCORE", "COMMITS", "FILE"], rows);
}
export function formatHotspotsCounts(raw) {
    const data = raw;
    return `${data.hotspots.length} hotspots, period: ${data.period}`;
}
const MAX_ROUTES_COMPACT = 25;
/** Grouped counts by router + rendering, then show top N URLs. */
export function formatNextjsRouteMapCompact(raw) {
    const data = raw;
    const lines = [];
    lines.push(`Routes: ${data.routes.length} | Conflicts: ${data.conflicts.length}`);
    const byRouter = {};
    const byRendering = {};
    for (const r of data.routes) {
        byRouter[r.router] = (byRouter[r.router] ?? 0) + 1;
        byRendering[r.rendering] = (byRendering[r.rendering] ?? 0) + 1;
    }
    const routerParts = Object.entries(byRouter).map(([k, v]) => `${k}=${v}`);
    const renderingParts = Object.entries(byRendering).map(([k, v]) => `${k}=${v}`);
    lines.push(`By router: ${routerParts.join(" ")}`);
    lines.push(`By rendering: ${renderingParts.join(" ")}`);
    if (data.middleware) {
        lines.push(`Middleware: ${data.middleware.file}`);
    }
    const top = data.routes.slice(0, MAX_ROUTES_COMPACT);
    for (const r of top) {
        lines.push(`  ${r.url_path} [${r.router}/${r.rendering}]`);
    }
    if (data.routes.length > MAX_ROUTES_COMPACT) {
        lines.push(`  ... +${data.routes.length - MAX_ROUTES_COMPACT} more`);
    }
    return lines.join("\n");
}
export function formatNextjsRouteMapCounts(raw) {
    const data = raw;
    return `${data.routes.length} routes, ${data.conflicts.length} conflicts, ${data.workspaces_scanned.length} workspaces`;
}
export function formatNextjsMetadataAuditCompact(raw) {
    const data = raw;
    const lines = [];
    lines.push(`${data.total_pages} pages | excellent=${data.counts.excellent} good=${data.counts.good} needs_work=${data.counts.needs_work} poor=${data.counts.poor}`);
    if (data.top_issues.length > 0) {
        lines.push(`Top: ${data.top_issues.slice(0, 5).join(" | ")}`);
    }
    // Show top 3 worst-scoring routes
    const worst = [...data.scores].sort((a, b) => a.score - b.score).slice(0, 3);
    for (const s of worst) {
        lines.push(`  ${s.url_path} (${s.score}/${s.grade})`);
    }
    return lines.join("\n");
}
export function formatNextjsMetadataAuditCounts(raw) {
    const data = raw;
    return `${data.total_pages} pages: excellent=${data.counts.excellent}, good=${data.counts.good}, needs_work=${data.counts.needs_work}, poor=${data.counts.poor}`;
}
export function formatFrameworkAuditCompact(raw) {
    const data = raw;
    const lines = [];
    lines.push(`Score: ${data.summary.overall_score}/100 (${data.summary.grade}) | ${data.duration_ms}ms`);
    if (data.summary.top_issues.length > 0) {
        lines.push(`Top: ${data.summary.top_issues.slice(0, 5).join(" | ")}`);
    }
    return lines.join("\n");
}
export function formatFrameworkAuditCounts(raw) {
    const data = raw;
    return `Score ${data.summary.overall_score}/100 (${data.summary.grade}), ${Object.keys(data.summary.dimensions).length} dimensions, ${data.tool_errors.length} errors`;
}
const MAX_VIOLATIONS_COMPACT = 5;
export function formatServerActionsAuditCompact(raw) {
    const data = raw;
    const lines = [];
    lines.push(`${data.total} actions | excellent=${data.counts.excellent} good=${data.counts.good} needs_work=${data.counts.needs_work} poor=${data.counts.poor}`);
    // Show top violations
    if (data.violations.length > 0) {
        lines.push(`Top violations: ${data.violations.slice(0, MAX_VIOLATIONS_COMPACT).join(" | ")}`);
    }
    // Show top 5 worst-scoring actions
    const worst = [...data.actions].sort((a, b) => a.score - b.score).slice(0, 5);
    for (const a of worst) {
        lines.push(`  ${a.file}:${a.line} ${a.name} (${a.score}/${a.grade})`);
    }
    if (data.parse_failures.length > 0) {
        lines.push(`parse failures: ${data.parse_failures.length}`);
    }
    return lines.join("\n");
}
export function formatServerActionsAuditCounts(raw) {
    const data = raw;
    const highSeverity = data.counts.poor + data.counts.needs_work;
    return `${data.total} actions audited, ${data.violations.length} violations (${highSeverity} high severity)`;
}
export function formatApiContractCompact(raw) {
    const data = raw;
    const lines = [];
    lines.push(`${data.total} endpoints | completeness ${data.completeness_score}%`);
    // Count handlers with resolved Zod schemas (completeness >= 0.5 means request_schema resolved)
    const withSchemas = data.handlers.filter((h) => h.completeness >= 0.5).length;
    lines.push(`With Zod schemas: ${withSchemas}/${data.total}`);
    // Show method/path/completeness per handler (no body schemas or response shapes)
    for (const h of data.handlers) {
        lines.push(`  ${h.method} ${h.path} (${Math.round(h.completeness * 100)}%) ${h.file}`);
    }
    if (data.parse_failures.length > 0) {
        lines.push(`parse failures: ${data.parse_failures.length}`);
    }
    return lines.join("\n");
}
export function formatApiContractCounts(raw) {
    const data = raw;
    const withSchemas = data.handlers.filter((h) => h.completeness >= 0.5).length;
    return `${data.total} endpoints, ${withSchemas} with Zod schemas, completeness ${data.completeness_score}%`;
}
const MAX_BOUNDARY_COMPACT = 10;
export function formatBoundaryAnalyzerCompact(raw) {
    const data = raw;
    const lines = [];
    lines.push(`${data.client_count} client components | total LOC ${data.total_client_loc}`);
    const top = data.entries.slice(0, MAX_BOUNDARY_COMPACT);
    const rows = top.map((e) => [
        String(e.rank),
        String(e.score),
        String(e.signals.loc),
        e.path,
    ]);
    lines.push(formatTable(["RANK", "SCORE", "LOC", "PATH"], rows));
    if (data.entries.length > MAX_BOUNDARY_COMPACT) {
        lines.push(`... +${data.entries.length - MAX_BOUNDARY_COMPACT} more`);
    }
    return lines.join("\n");
}
export function formatBoundaryAnalyzerCounts(raw) {
    const data = raw;
    const topName = data.largest_offender?.path ?? "none";
    return `${data.client_count} client components, total LOC ${data.total_client_loc}, top offender: ${topName}`;
}
//# sourceMappingURL=formatters-shortening.js.map