/**
 * Server PluginHost — singleton holding registered BackendModule manifests +
 * activation state. M13 spec: this is the *single* abstraction layer for
 * entity types. All consumers (chat-context, serializer registry, MCP, L4
 * routes) ask the host instead of iterating type literals.
 *
 * Phase 0: only registration + lookup. mountBackend is a stub that becomes
 * the unified mount point in Phase 3.
 */
import { diffEntity, restoreEntity, snapshotEntity } from '../../serialization/snapshot.js';
class PluginHostImpl {
    modules = new Map();
    activeTypes = null; // null = all active
    unknownTypes = [];
    idResolvers = new Map();
    mcpServerFactories = new Map();
    entityServices = new Map();
    registerBackendModule(module) {
        if (!module.type) {
            throw new Error('plugin-host: module.type is required');
        }
        this.modules.set(module.type, module);
    }
    consolidate(activeWhitelist) {
        if (activeWhitelist == null) {
            this.activeTypes = null;
            this.unknownTypes = [];
            return;
        }
        const active = new Set();
        const unknown = [];
        for (const type of activeWhitelist) {
            if (this.modules.has(type))
                active.add(type);
            else
                unknown.push(type);
        }
        this.activeTypes = active;
        this.unknownTypes = unknown;
    }
    listAvailable() {
        return Array.from(this.modules.values()).sort((a, b) => a.displayOrder - b.displayOrder);
    }
    listEntities() {
        return this.listAvailable().filter((m) => this.isActive(m.type));
    }
    getEntity(type) {
        if (!this.isActive(type))
            return null;
        return this.modules.get(type) ?? null;
    }
    getAvailable(type) {
        return this.modules.get(type) ?? null;
    }
    isActive(type) {
        if (!this.modules.has(type))
            return false;
        if (this.activeTypes == null)
            return true;
        return this.activeTypes.has(type);
    }
    state() {
        const active = this.listEntities().map((m) => m.type);
        const inactive = this.listAvailable()
            .filter((m) => !this.isActive(m.type))
            .map((m) => m.type);
        return { active, inactive, unknown: [...this.unknownTypes] };
    }
    mountBackend(ctx) {
        for (const m of this.listEntities()) {
            m.backend?.mount?.(ctx);
        }
    }
    registerMcpServer(name, factory) {
        this.mcpServerFactories.set(name, factory);
    }
    buildMcpServers() {
        return Array.from(this.mcpServerFactories.entries()).map(([name, factory]) => ({
            name,
            server: factory(),
        }));
    }
    setIdResolver(type, fn) {
        this.idResolvers.set(type, fn);
    }
    resolveEntityId(type, slug) {
        const fn = this.idResolvers.get(type);
        return fn ? fn(slug) : null;
    }
    entityExists(type, slug) {
        return this.resolveEntityId(type, slug) !== null;
    }
    registerEntityService(type, service) {
        this.entityServices.set(type, service);
    }
    getEntityService(type) {
        return this.entityServices.get(type) ?? null;
    }
    // ─── M17 snapshot helpers ────────────────────────────────────────────────
    snapshot(type, entity, ctx) {
        return snapshotEntity(this, type, entity, ctx);
    }
    restore(type, data, ctx) {
        return restoreEntity(this, type, data, ctx);
    }
    diff(type, a, b, slug) {
        return diffEntity(this, type, a, b, slug);
    }
    computeEntityCounts(db) {
        const counts = {};
        for (const m of this.listEntities()) {
            const sql = m.systemPrompt.countStat.sqlQuery;
            if (!sql)
                continue;
            try {
                const row = db.prepare(sql).get();
                counts[m.type] = row?.count ?? 0;
            }
            catch (err) {
                console.warn(`[plugin-host] computeEntityCounts: countStat query failed for type=${m.type}: ${err.message}`);
                counts[m.type] = 0;
            }
        }
        return counts;
    }
}
export const pluginHost = new PluginHostImpl();
//# sourceMappingURL=host.js.map