/**
 * Governance handler group: runtime_health, doctor, autofix, audit_evolution,
 * graph_query, hypertune_max.
 * Extracted from mcp.ts (Phase 3 split).
 */
import { formatBullets, formatJsonDetails, getGraphEngine, getTraversalEngine, getHybridRetriever, } from '../helpers.js';
import { getTokenEngine } from '../util/token-engine.js';
import { nexusEventBus } from '../../../../engines/event-bus.js';
import { formatBrandedResponse } from '../../../../engines/nexus-brand.js';
import { formatReadingPlan } from '../../../../engines/token-supremacy.js';
import { ContextAssembler } from '../../../../engines/context-assembler.js';
import { pLimit } from '../../../../engines/util/p-limit.js';
import { promises as fsPromises, statSync } from 'fs';
import * as path from 'path';
import { resolveNexusStateDir } from '../../../../engines/runtime-registry.js';
import { getCircuitManager } from '../circuit.js';
import { getSharedAuditLog } from '../../../../engines/security-shield.js';
import { ensureBootstrap } from '../../../../engines/client-bootstrap.js';
import { HybridRetriever } from '../../../../engines/hybrid-retriever.js';
import { GraphTraversalEngine } from '../../../../engines/graph-traversal.js';
import { fileURLToPath } from 'url';
import { requireRuntime } from '../util/require-runtime.js';
import { getAllPerfStats } from '../../../../engines/perf-history.js';
import { getTTVSnapshot } from '../../../../engines/telemetry.js';
import { getProviderRegistry } from '../../../../engines/providers/index.js';
const _gfile = fileURLToPath(import.meta.url);
const PROJECT_ROOT = path.resolve(path.dirname(_gfile), '..', '..', '..', '..', '..');
export async function handleGovernanceGroup(toolName, hctx, request, args, ctx) {
    const runtimeError = requireRuntime(hctx);
    if (runtimeError)
        return runtimeError;
    switch (toolName) {
        case 'nexus_runtime_health': {
            const envelope = hctx.nexusRef.getRuntimeHealthEnvelope();
            const circuitStats = getCircuitManager().getAllStats();
            const inFlight = getCircuitManager().getInFlight();
            const trippedCircuits = circuitStats.filter(s => s.state !== 'closed');
            const providerReg = getProviderRegistry();
            const cooledDown = providerReg.getCooldowns();
            const totalCost = providerReg.getTotalCost();
            return {
                content: [{
                        type: 'text',
                        text: [
                            `Runtime health: ${envelope.status}`,
                            formatBullets([
                                `Workspace: ${envelope.workspace.workspaceRoot}`,
                                `Repo root: ${envelope.workspace.repoRoot}`,
                                `Synapse: ${envelope.engines.synapse.mode} (${envelope.engines.synapse.storageRoot || 'n/a'})`,
                                `Architects: ${envelope.engines.architects.mode} (${envelope.engines.architects.storageRoot || 'n/a'})`,
                                `Primary client: ${envelope.clients.primaryClientId || 'none'}`,
                                `In-flight calls: ${inFlight}/100`,
                                trippedCircuits.length > 0
                                    ? `Tripped circuits: ${trippedCircuits.map(c => `${c.tool}(${c.state},p99=${Math.round(c.p99Ms)}ms)`).join(', ')}`
                                    : 'Circuits: all closed',
                                `Provider cost (session): $${totalCost.toFixed(4)}`,
                                cooledDown.length > 0
                                    ? `Rate-limited models: ${cooledDown.map(c => `${c.modelId}(${Math.ceil(c.expiresIn / 1000)}s)`).join(', ')}`
                                    : 'Models: all available',
                            ]),
                            formatJsonDetails('Structured details', { ...envelope, circuits: circuitStats, providers: providerReg.getReceipts(undefined, 10) }),
                        ].join('\n\n'),
                    }],
            };
        }
        case 'nexus_doctor': {
            const envelope = hctx.nexusRef.getRuntimeHealthEnvelope();
            const bootstrap = hctx.getRuntime().getUsageSnapshot()?.bootstrapManifestStatus;
            const rotateBytes = (() => {
                const raw = process.env.NEXUS_NGRAM_ROTATE_BYTES;
                const parsed = raw ? Number(raw) : NaN;
                return Number.isFinite(parsed) && parsed > 0 ? Math.floor(parsed) : 1024 * 1024 * 1024;
            })();
            const ngramDbPath = path.join(resolveNexusStateDir(), 'ngram-index.db');
            let ngramSizeBytes = 0;
            try {
                ngramSizeBytes = statSync(ngramDbPath).size;
            }
            catch { /* missing */ }
            const ngramOversized = ngramSizeBytes >= rotateBytes && ngramSizeBytes > 0;
            // ── Honest subsystem liveness checks ─────────────────────────
            const synapseLive = !!hctx.nexusRef.getSynapse?.();
            const architectsLive = !!hctx.nexusRef.getArchitects?.();
            const memoryLive = envelope.memory.available;
            const orchestratorLive = envelope.runtime.available;
            const subsystems = [
                { name: 'Memory', live: memoryLive, fix: 'Check ~/.nexus-prime/memory.db — recreate if corrupt.' },
                { name: 'Orchestrator', live: orchestratorLive, fix: 'Run nexus_autofix — orchestrator binds on first bootstrap.' },
                { name: 'Synapse', live: synapseLive, fix: 'Call any nexus_synapse_* tool to trigger lazy-init, or set NEXUS_SYNAPSE_LAZY=0.' },
                { name: 'Architects', live: architectsLive, fix: 'Call any nexus_architects_* tool to trigger lazy-init, or set NEXUS_ARCHITECTS_LAZY=0.' },
            ];
            const deadSubsystems = subsystems.filter((s) => !s.live);
            const issues = [
                ...envelope.degradedReasons,
                ...deadSubsystems.map((s) => `${s.name} is NOT running. Fix: ${s.fix}`),
                ...(bootstrap?.clients ?? [])
                    .filter((client) => client.state !== 'installed')
                    .map((client) => `${client.label}: ${client.summary}`),
                ...(ngramOversized
                    ? [`Ngram index oversized: ${Math.round(ngramSizeBytes / 1024 / 1024)}MB (>= ${Math.round(rotateBytes / 1024 / 1024)}MB) db=${ngramDbPath}`]
                    : []),
            ];
            const allLive = deadSubsystems.length === 0;
            // ── perfProfile: p50/p90/p99 per tool + TTV snapshot ─────────
            const [perfStats, ttvSnap] = await Promise.all([
                getAllPerfStats().catch(() => []),
                Promise.resolve(getTTVSnapshot()),
            ]);
            const perfProfile = {
                tools: perfStats.map((s) => ({
                    tool: s.tool,
                    count: s.count,
                    p50ms: s.p50,
                    p90ms: s.p90,
                    p99ms: s.p99,
                    budget: s.budget ?? null,
                    slow: s.budget ? s.p99 > s.budget.fail : false,
                })),
                ttv: {
                    daemonStartAt: ttvSnap.daemonStartAt,
                    firstBootstrapMs: ttvSnap.firstBootstrapAt != null ? ttvSnap.firstBootstrapAt - ttvSnap.daemonStartAt : null,
                    firstMemoryMs: ttvSnap.firstMemoryAt != null ? ttvSnap.firstMemoryAt - ttvSnap.daemonStartAt : null,
                    firstInteractionMs: ttvSnap.firstInteractionAt != null ? ttvSnap.firstInteractionAt - ttvSnap.daemonStartAt : null,
                    firstMissionMs: ttvSnap.firstMissionCompleteAt != null ? ttvSnap.firstMissionCompleteAt - ttvSnap.daemonStartAt : null,
                },
            };
            const slowTools = perfProfile.tools.filter((t) => t.slow).map((t) => t.tool);
            return {
                content: [{
                        type: 'text',
                        text: [
                            formatBrandedResponse({
                                toolName: 'nexus_doctor',
                                body: allLive
                                    ? `All ${subsystems.length} subsystems nominal.`
                                    : `${deadSubsystems.length}/${subsystems.length} subsystems DOWN.`,
                                includeQuote: true,
                            }),
                            formatBullets([
                                ...subsystems.map((s) => `${s.live ? '\u2705' : '\u274C'} ${s.name}: ${s.live ? 'LIVE' : 'DOWN'}`),
                                `Workspace: ${envelope.workspace.source}`,
                                `Issues: ${issues.length}`,
                                `Ngram index: ${ngramOversized ? 'oversized' : 'ok'} (${Math.round(ngramSizeBytes / 1024 / 1024)}MB)`,
                                ...(slowTools.length > 0 ? [`\u26A0\uFE0F Slow tools (p99 > budget): ${slowTools.join(', ')}`] : []),
                            ]),
                            issues.length > 0 ? formatBullets(issues.map((issue) => `\u26A0\uFE0F ${issue}`)) : '',
                            (() => {
                                const auditSummary = getSharedAuditLog().getSummary();
                                const sealedStr = auditSummary.sealedMode ? ' [SEALED MODE]' : '';
                                return formatBullets([
                                    `\uD83D\uDEE1\uFE0F Security${sealedStr}: ${auditSummary.totalDecisions} decisions (${auditSummary.blocked} blocked)`,
                                    `   allow: ${auditSummary.byAction.allow}  warn: ${auditSummary.byAction.warn}  quarantine: ${auditSummary.byAction.quarantine}  block: ${auditSummary.byAction.block}`,
                                ]);
                            })(),
                            formatJsonDetails('Structured details', {
                                subsystems: subsystems.map((s) => ({ name: s.name, live: s.live, fix: s.live ? null : s.fix })),
                                envelope,
                                issues,
                                ngramIndex: {
                                    dbPath: ngramDbPath,
                                    sizeBytes: ngramSizeBytes,
                                    rotateBytes,
                                    oversized: ngramOversized,
                                },
                                securityAudit: getSharedAuditLog().getSummary(),
                                perfProfile,
                            }),
                        ].filter(Boolean).join('\n\n'),
                    }],
            };
        }
        case 'nexus_autofix': {
            const manifest = ensureBootstrap({
                packageRoot: PROJECT_ROOT,
                workspaceRoot: hctx.nexusRef.getWorkspaceContext().workspaceRoot,
                phase: 'install',
                silent: true,
            });
            const memoryMaintenance = hctx.nexusRef.maintainMemory();
            const ngramIndexMaintenance = memoryMaintenance?.ngramIndex ?? null;
            hctx.getRuntime().recordBootstrapManifestStatus?.(manifest);
            const envelope = hctx.nexusRef.getRuntimeHealthEnvelope();
            return {
                content: [{
                        type: 'text',
                        text: [
                            'Autofix completed.',
                            formatBullets([
                                `Bootstrap clients tracked: ${manifest.clients.length}`,
                                `Memory expired: ${Number(memoryMaintenance?.expired || 0)}`,
                                `Memory quarantined: ${Number(memoryMaintenance?.quarantined || 0)}`,
                                `Ngram index: ${ngramIndexMaintenance?.action || 'n/a'}`,
                                `Runtime status: ${envelope.status}`,
                            ]),
                            formatJsonDetails('Structured details', {
                                manifest,
                                memoryMaintenance,
                                ngramIndexMaintenance,
                                envelope,
                            }),
                        ].join('\n\n'),
                    }],
            };
        }
        case 'nexus_audit_evolution': {
            const { candidates, hotspots, recommendations } = await hctx.nexusRef.auditEvolution();
            const lines = ['🧬 Evolution Audit Report', ''];
            // Recommendations first (most actionable)
            if (recommendations.length > 0) {
                lines.push('## Recommendations');
                for (const rec of recommendations)
                    lines.push(`  ${rec}`);
                lines.push('');
            }
            // Hotspots
            if (hotspots.size > 0) {
                lines.push('## File Hotspots (conflict frequency)');
                for (const [file, count] of [...hotspots.entries()].sort((a, b) => b[1] - a[1])) {
                    lines.push(`  ${count}x  ${file}`);
                }
                lines.push('');
            }
            // Raw candidates count
            lines.push(`📊 ${candidates.length} evolution candidate(s) in memory.`);
            return {
                content: [{ type: 'text', text: lines.join('\n') }]
            };
        }
        case 'nexus_graph_query': {
            const action = String(request.params.arguments?.action ?? 'query');
            const query = String(request.params.arguments?.query ?? '');
            const depth = Number(request.params.arguments?.depth ?? 2);
            switch (action) {
                case 'query': {
                    const retriever = getHybridRetriever();
                    const result = await retriever.retrieve(query, 10, depth);
                    const formatted = HybridRetriever.format(result);
                    return { content: [{ type: 'text', text: formatted }] };
                }
                case 'traverse': {
                    const traversal = getTraversalEngine();
                    const result = traversal.queryByName(query, depth);
                    const formatted = GraphTraversalEngine.format(result);
                    return { content: [{ type: 'text', text: formatted }] };
                }
                case 'centrality': {
                    const traversal = getTraversalEngine();
                    const scores = traversal.computeCentrality(20);
                    if (scores.length === 0) {
                        return { content: [{ type: 'text', text: '📭 No entities in graph yet.' }] };
                    }
                    const lines = ['📊 Entity Centrality (top 20):', ''];
                    for (const s of scores) {
                        lines.push(`  • ${s.entityName} — score: ${s.score.toFixed(3)} (in: ${s.inDegree}, out: ${s.outDegree})`);
                    }
                    return { content: [{ type: 'text', text: lines.join('\n') }] };
                }
                case 'ingest': {
                    const text = String(request.params.arguments?.text ?? '');
                    const tags = Array.isArray(request.params.arguments?.tags)
                        ? request.params.arguments.tags.map(String) : [];
                    const graph = getGraphEngine();
                    const { entities, relations } = graph.ingestFromText(text, tags);
                    return {
                        content: [{
                                type: 'text',
                                text: `✅ Ingested: ${entities.length} entities, ${relations.length} relations extracted and stored in graph.`,
                            }],
                    };
                }
                default:
                    return { content: [{ type: 'text', text: `Unknown graph action: ${action}` }] };
            }
        }
        case 'nexus_hypertune_max': {
            const task = String(request.params.arguments?.task ?? '');
            const rawFiles = Array.isArray(request.params.arguments?.files)
                ? request.params.arguments.files.map(String)
                : null;
            const filePaths = rawFiles
                ?? await hctx.scanSourceFiles(hctx.getWorkspace(request.params.arguments ?? {}).repoRoot);
            const statLimit = pLimit(8);
            const files = (await Promise.all(filePaths.map((p) => statLimit(async () => {
                const resolved = hctx.resolveToolPath(p, request.params.arguments ?? {});
                try {
                    const stat = await fsPromises.stat(resolved);
                    return { path: resolved, sizeBytes: stat.size, lastModified: stat.mtimeMs };
                }
                catch {
                    return { path: resolved, sizeBytes: 0 };
                }
            })))).filter((f) => f.sizeBytes > 0);
            const { plan, assembly, budgetConfig } = await getTokenEngine().hypertuneMax(task, files);
            const planText = formatReadingPlan(plan);
            const assemblyText = ContextAssembler.format(assembly, budgetConfig);
            const savings = plan.savings;
            const pct = plan.totalEstimatedTokens + savings > 0
                ? Math.round((savings / (plan.totalEstimatedTokens + savings)) * 100)
                : 0;
            hctx.telemetry.recordTokens(savings);
            nexusEventBus.emit('tokens.optimized', { savings, pct, files: files.length });
            const notification = hctx.telemetry.notifyTokens(task, savings, pct, files.length);
            const nudge = hctx.telemetry.planningNudge('optimize', { savings, pct });
            return {
                content: [{
                        type: 'text',
                        text: `${assemblyText}\n\n${planText}${notification}${nudge}`,
                    }],
            };
        }
    }
    return undefined;
}
