import { createHash } from "node:crypto";
import { buildCaeAdvisoryInstructionSurfaceBlock } from "./cae/cae-instruction-surface-advisory.js";
import { buildErrorRemediationCatalog } from "./cli-remediation.js";
import { isSensitiveModuleCommandForEffective, resolvePolicyOperationIdForCommand } from "./policy.js";
export function isAgentInstructionSurfaceFull(surface) {
    return surface.projection !== "lean";
}
/**
 * Classifies whether an instruction can be executed via the command router for the
 * current enabled module set (owning module enabled + all requiresPeers enabled).
 */
export function classifyInstructionExecution(mod, entry, registry) {
    const moduleId = mod.registration.id;
    if (!registry.isModuleEnabled(moduleId)) {
        return { kind: "module_disabled" };
    }
    const requires = entry.requiresPeers ?? [];
    const missing = requires.filter((peerId) => !registry.isModuleEnabled(peerId));
    if (missing.length > 0) {
        return { kind: "peer_disabled", missingPeers: missing };
    }
    return { kind: "executable" };
}
export function isInstructionExecutableForRegistry(mod, entry, registry) {
    return classifyInstructionExecution(mod, entry, registry).kind === "executable";
}
function stableInstructionRowJSON(row) {
    const degradation = row.degradation.kind === "peer_disabled"
        ? {
            kind: row.degradation.kind,
            missingPeers: [...row.degradation.missingPeers].sort()
        }
        : { kind: row.degradation.kind };
    const base = {
        commandName: row.commandName,
        degradation,
        executable: row.executable,
        instructionPath: row.instructionPath,
        moduleId: row.moduleId
    };
    if (row.jsonApprovalRequired !== undefined) {
        base.jsonApprovalRequired = row.jsonApprovalRequired;
    }
    if (row.policyOperationId !== undefined) {
        base.policyOperationId = row.policyOperationId;
    }
    return JSON.stringify(base);
}
/** Stable digest over the sorted command row set (for lean projection cache hits). */
export function digestAgentInstructionSurfaceCommands(commands) {
    const body = commands.map(stableInstructionRowJSON).join("\n");
    return `sha256:${createHash("sha256").update(body).digest("hex")}`;
}
function collectInstructionSurfaceRows(allModules, registry, effectiveConfig) {
    const commands = [];
    for (const mod of allModules) {
        const moduleId = mod.registration.id;
        const { directory, entries } = mod.registration.instructions;
        for (const entry of entries) {
            const degradation = classifyInstructionExecution(mod, entry, registry);
            const instructionPath = `${directory}/${entry.file}`.replace(/\\/g, "/");
            const executable = degradation.kind === "executable";
            const row = {
                commandName: entry.name,
                moduleId,
                instructionPath,
                executable,
                degradation
            };
            if (effectiveConfig && executable) {
                row.jsonApprovalRequired = isSensitiveModuleCommandForEffective(entry.name, {}, effectiveConfig);
                row.policyOperationId = resolvePolicyOperationIdForCommand(entry.name, effectiveConfig);
            }
            commands.push(row);
        }
    }
    commands.sort((a, b) => a.commandName.localeCompare(b.commandName));
    return commands;
}
export function buildAgentInstructionSurface(allModules, registry, options) {
    const commands = collectInstructionSurfaceRows(allModules, registry, options?.effectiveConfig);
    const activationReport = registry.getActivationReport();
    const errorRemediationCatalog = {
        schemaVersion: 1,
        entries: buildErrorRemediationCatalog()
    };
    const ws = options?.workspacePath;
    const eff = options?.effectiveConfig;
    let cae;
    if (ws && eff) {
        cae = buildCaeAdvisoryInstructionSurfaceBlock(ws, eff) ?? undefined;
    }
    if (options?.projection === "lean") {
        const executable = commands.filter((c) => c.executable).length;
        const lean = {
            schemaVersion: 1,
            projection: "lean",
            instructionSurfaceDigest: digestAgentInstructionSurfaceCommands(commands),
            commandCounts: {
                total: commands.length,
                executable,
                documentationOnly: commands.length - executable
            },
            activationReport,
            errorRemediationCatalog
        };
        if (cae)
            lean.cae = cae;
        return lean;
    }
    const full = {
        schemaVersion: 1,
        commands,
        activationReport,
        errorRemediationCatalog
    };
    if (cae)
        full.cae = cae;
    return full;
}
