/**
 * SerializationEngine — host-driven dispatch for L9 entity serialization.
 *
 * Host-driven L9 dispatch (M13). All entity serializers come
 * from the plugin host's `BackendModule.serializer` slot; the only internal
 * registration is the `section` non-entity serializer, kept here because
 * section is not a plugin (M06 owns it).
 */
import { fallbackEntity, fallbackSection } from '../../serialization/fallback.js';
import { autoDerivedSchema } from '../../serialization/auto-schema.js';
import { pluginHost } from './host.js';
const MAX_DEPTH = 1;
class SerializationEngineImpl {
    /** Section serializer is registered separately — section is not an entity. */
    sectionSerializer = null;
    attachSectionSerializer(serializer) {
        this.sectionSerializer = serializer;
    }
    has(type) {
        if (type === 'section')
            return this.sectionSerializer !== null;
        return pluginHost.getAvailable(type) !== null;
    }
    get(type) {
        if (type === 'section')
            return this.sectionSerializer ?? undefined;
        return pluginHost.getAvailable(type)?.serializer;
    }
    listTypes() {
        const types = pluginHost.listAvailable().map((m) => m.type);
        if (this.sectionSerializer)
            types.push('section');
        return types.sort();
    }
    getVersion(type) {
        return this.get(type)?.version ?? null;
    }
    serializeEntity(type, view, entity, reader, depth = 0) {
        return this.invoke(type, view, entity, reader, depth, () => fallbackEntity(entity, view));
    }
    serializeSection(view, section, reader) {
        return this.invoke('section', view, section, reader, 0, () => fallbackSection(section, view));
    }
    invoke(type, view, input, reader, depth, buildFallback) {
        const serializer = this.get(type);
        if (!serializer) {
            return { data: buildFallback(), fallback: true, error: 'no_serializer' };
        }
        const method = pickMethod(serializer, view);
        if (!method) {
            return { data: buildFallback(), fallback: true };
        }
        const ctx = { reader, depth, maxDepth: MAX_DEPTH };
        try {
            const data = method(input, ctx);
            const brokenRefs = extractBrokenRefs(data);
            return { data, fallback: false, ...(brokenRefs ? { brokenRefs } : {}) };
        }
        catch (err) {
            return {
                data: buildFallback(),
                fallback: true,
                error: `serializer_threw: ${err.message}`,
            };
        }
    }
    getSchema(type, view, db) {
        const serializer = this.get(type);
        if (serializer?.schema)
            return serializer.schema(view);
        if (db)
            return autoDerivedSchema(db, type);
        return { type: 'object', _auto: true, _note: 'schema unavailable without db handle' };
    }
    catalog(reader, db) {
        const types = {};
        for (const t of this.listTypes()) {
            const serializer = this.get(t);
            if (!serializer)
                continue;
            const views = [];
            if (serializer.inlineMention)
                views.push('inline_mention');
            if (serializer.singleElement)
                views.push('single_element');
            if (serializer.elementListItem)
                views.push('element_list_item');
            if (serializer.taggedListItem)
                views.push('tagged_list_item');
            if (serializer.detail)
                views.push('detail');
            const schemas = {};
            const viewList = [
                'inline_mention',
                'single_element',
                'element_list_item',
                'tagged_list_item',
                'detail',
            ];
            for (const view of viewList) {
                schemas[view] = this.getSchema(t, view, db);
            }
            types[t] = { version: serializer.version, views, schemas };
        }
        void reader;
        return { types };
    }
}
export const serializationEngine = new SerializationEngineImpl();
function pickMethod(serializer, view) {
    switch (view) {
        case 'inline_mention':
            return serializer.inlineMention;
        case 'single_element':
            return serializer.singleElement;
        case 'element_list_item':
            return serializer.elementListItem;
        case 'tagged_list_item':
            return serializer.taggedListItem;
        case 'detail':
            return serializer.detail;
    }
}
function extractBrokenRefs(data) {
    if (!data || typeof data !== 'object')
        return undefined;
    const refs = data._brokenRefs;
    if (Array.isArray(refs) && refs.every((r) => typeof r === 'string'))
        return refs;
    return undefined;
}
//# sourceMappingURL=serialization-engine.js.map