"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.readMcpDeclaredToolsets = readMcpDeclaredToolsets;
exports.buildToolsetAuditReport = buildToolsetAuditReport;
exports.hasHardToolsetAuditFailures = hasHardToolsetAuditFailures;
exports.printToolsetAudit = printToolsetAudit;
const promises_1 = require("fs/promises");
const config_1 = require("../mcp/config");
const registry_1 = require("../tools/registry");
function listExplicitToolsets(member) {
    if (!member.toolsets)
        return [];
    const out = [];
    const seen = new Set();
    for (const entry of member.toolsets) {
        if (entry === '*' || entry.startsWith('!'))
            continue;
        if (seen.has(entry))
            continue;
        seen.add(entry);
        out.push(entry);
    }
    return out;
}
async function readMcpDeclaredToolsets() {
    const mcpPath = '.minds/mcp.yaml';
    let raw;
    try {
        raw = await (0, promises_1.readFile)(mcpPath, 'utf8');
    }
    catch (err) {
        if (typeof err === 'object' &&
            err !== null &&
            'code' in err &&
            err.code === 'ENOENT') {
            return { kind: 'missing' };
        }
        return { kind: 'invalid', errorText: err instanceof Error ? err.message : String(err) };
    }
    const parsed = (0, config_1.parseMcpYaml)(raw);
    if (!parsed.ok) {
        return { kind: 'invalid', errorText: parsed.errorText };
    }
    return {
        kind: 'loaded',
        declaredServerIds: new Set(parsed.serverIdsInYamlOrder),
        invalidServerIds: new Set(parsed.invalidServers.map((s) => s.serverId)),
        disabledServerIds: new Set(parsed.disabledServerIdsInYamlOrder),
    };
}
function buildToolsetAuditReport(params) {
    const registeredToolsets = new Set(Object.keys((0, registry_1.listToolsets)()));
    const byMember = [];
    const warnings = [];
    for (const memberId of params.targetMemberIds) {
        const member = params.team.getMember(memberId);
        if (!member)
            continue;
        const explicitToolsets = listExplicitToolsets(member);
        const items = [];
        for (const toolsetName of explicitToolsets) {
            if (params.mcp.kind === 'loaded' && params.mcp.declaredServerIds.has(toolsetName)) {
                if (params.mcp.invalidServerIds.has(toolsetName)) {
                    items.push({ toolsetName, status: 'mcp_declared_invalid' });
                    warnings.push(`@${member.id}: toolset '${toolsetName}' is declared in mcp.yaml but server config is invalid.`);
                }
                else if (params.mcp.disabledServerIds.has(toolsetName)) {
                    items.push({ toolsetName, status: 'mcp_declared_disabled' });
                }
                else {
                    if (registeredToolsets.has(toolsetName)) {
                        items.push({ toolsetName, status: 'registered' });
                    }
                    else {
                        items.push({ toolsetName, status: 'mcp_declared_unloaded' });
                    }
                }
                continue;
            }
            if (registeredToolsets.has(toolsetName)) {
                items.push({ toolsetName, status: 'registered' });
                continue;
            }
            items.push({ toolsetName, status: 'missing' });
            warnings.push(`@${member.id}: toolset '${toolsetName}' is neither registered nor declared in mcp.yaml.`);
        }
        byMember.push({ memberId: member.id, memberName: member.name, items });
    }
    if (params.mcp.kind === 'invalid') {
        warnings.push(`Invalid .minds/mcp.yaml; cannot reliably classify unresolved MCP toolsets: ${params.mcp.errorText}`);
    }
    return {
        mcp: params.mcp,
        byMember,
        warnings,
    };
}
function countByStatus(report) {
    const counts = {
        registered: 0,
        mcp_declared_unloaded: 0,
        mcp_declared_invalid: 0,
        mcp_declared_disabled: 0,
        missing: 0,
    };
    for (const memberReport of report.byMember) {
        for (const item of memberReport.items) {
            counts[item.status] += 1;
        }
    }
    return counts;
}
function statusLabel(status) {
    if (status === 'registered')
        return 'OK';
    if (status === 'mcp_declared_unloaded')
        return 'DEFERRED';
    if (status === 'mcp_declared_invalid')
        return 'INVALID';
    if (status === 'mcp_declared_disabled')
        return 'DISABLED';
    return 'MISS';
}
function hasHardToolsetAuditFailures(report) {
    if (report.mcp.kind === 'invalid')
        return true;
    return report.byMember.some((memberReport) => memberReport.items.some((item) => item.status === 'mcp_declared_invalid' || item.status === 'missing'));
}
function printToolsetAudit(report, options) {
    const heading = options?.heading ?? '## Toolset Audit';
    const counts = countByStatus(report);
    process.stdout.write(`\n${heading}\n`);
    if (report.mcp.kind === 'missing') {
        process.stdout.write('- MCP config: missing (`.minds/mcp.yaml` not found)\n');
    }
    else if (report.mcp.kind === 'invalid') {
        process.stdout.write('- MCP config: invalid (`.minds/mcp.yaml` parse/read failed)\n');
    }
    else {
        process.stdout.write(`- MCP config: loaded (declared servers: ${report.mcp.declaredServerIds.size}, invalid server configs: ${report.mcp.invalidServerIds.size}, disabled servers: ${report.mcp.disabledServerIds.size})\n`);
    }
    process.stdout.write(`- Summary: ${counts.registered} OK, ${counts.mcp_declared_unloaded} DEFERRED, ${counts.mcp_declared_disabled} DISABLED, ${counts.mcp_declared_invalid} INVALID, ${counts.missing} MISS\n`);
    if (options?.includeTransientLegend !== false) {
        process.stdout.write('- Status notes: `DEFERRED` means the toolset is declared via `.minds/mcp.yaml` but is not currently loaded into the registry. This is often temporary (for example MCP server down/unreachable); if the MCP service recovers, rerun validation and it may clear without editing `team.yaml`.\n');
        process.stdout.write('- Status notes: `DISABLED` means the MCP server has `enabled: false`; it remains declared but intentionally exposes zero tools until `mcp_restart` enables it. `INVALID` means the MCP server declaration itself is invalid and needs a config fix. `MISS` means the toolset is neither registered nor declared in `.minds/mcp.yaml`.\n');
    }
    if (report.byMember.length === 0) {
        process.stdout.write('- Members: none\n');
    }
    else {
        for (const memberReport of report.byMember) {
            process.stdout.write(`- @${memberReport.memberId} (${memberReport.memberName}):\n`);
            if (memberReport.items.length === 0) {
                process.stdout.write('  - no explicit toolset declarations\n');
                continue;
            }
            for (const item of memberReport.items) {
                process.stdout.write(`  - [${statusLabel(item.status)}] ${item.toolsetName}\n`);
            }
        }
    }
    if (report.warnings.length > 0) {
        process.stdout.write('- Warnings:\n');
        for (const warning of report.warnings) {
            process.stdout.write(`  - ${warning}\n`);
        }
    }
    else {
        process.stdout.write('- Warnings: none\n');
    }
}
