/**
 * Imported-event payload typing — the messaging-emitter counterpart to the
 * operation-signature extractor (#81-adjacent).
 *
 * A messaging `import:` publishes EVENTS (the dotted/bare select entries name
 * events), so the meaningful "real type" is the PAYLOAD — the published event's
 * attribute shape, not an operation's params/return. This module parses the
 * provider `.specly`, matches each select entry to an event in the provider's
 * `events:` section, and derives an inline payload object type (`{ orderId:
 * string; total: Money }`), referencing provider models by interface name.
 *
 * Matching is heuristic (the select grammar `Order.created` maps by convention
 * to a PascalCase event `OrderCreated`): an entry resolves if it (or its
 * head+tail PascalCase) names a provider event. Unmatched entries are
 * `remaining` (the caller keeps `payload: unknown`).
 */
import * as yaml from 'js-yaml';
import { parseAttr, mapAttrType, isRequired, collectModels, emitInterface, } from './imported-model-types.js';
function collectEvents(parsed) {
    const events = new Map();
    const components = parsed?.components;
    if (!components || typeof components !== 'object')
        return events;
    for (const comp of Object.values(components)) {
        const compEvents = comp?.events;
        if (compEvents && typeof compEvents === 'object') {
            for (const [name, def] of Object.entries(compEvents)) {
                events.set(name, (def ?? {}));
            }
        }
    }
    return events;
}
/** Candidate event names for a select entry (`Order.created` → `OrderCreated`). */
function eventCandidates(entry) {
    const dot = entry.indexOf('.');
    if (dot === -1)
        return [entry];
    const head = entry.slice(0, dot);
    const tail = entry.slice(dot + 1);
    const cap = (s) => (s ? s.charAt(0).toUpperCase() + s.slice(1) : s);
    return Array.from(new Set([entry, `${cap(head)}${cap(tail)}`, `${head}${cap(tail)}`]));
}
export function extractImportedEventPayloads(specContent, selectEntries) {
    let parsed;
    try {
        parsed = yaml.load(specContent);
    }
    catch {
        return { payloads: new Map(), modelInterfaces: [], referencedModels: [], emitted: [], remaining: [...selectEntries] };
    }
    const events = collectEvents(parsed);
    const models = collectModels(parsed);
    const modelNames = new Set(models.keys());
    const referenced = new Set();
    const payloads = new Map();
    const emitted = [];
    const remaining = [];
    for (const entry of selectEntries) {
        const match = eventCandidates(entry).map((c) => events.get(c)).find((d) => !!d);
        if (!match) {
            remaining.push(entry);
            continue;
        }
        const attrs = (match.attributes ?? {});
        const fields = Object.entries(attrs).map(([name, t]) => {
            const p = parseAttr(t);
            let ts;
            if (p.base && modelNames.has(p.base)) {
                referenced.add(p.base);
                ts = p.isArray ? `${p.base}[]` : p.base;
            }
            else {
                ts = mapAttrType(t);
            }
            return `${name}${isRequired(t) ? '' : '?'}: ${ts}`;
        });
        payloads.set(entry, fields.length ? `{ ${fields.join('; ')} }` : 'Record<string, unknown>');
        emitted.push(entry);
    }
    const referencedModels = Array.from(referenced).filter((n) => models.has(n));
    const modelInterfaces = referencedModels.map((n) => emitInterface(n, models.get(n)));
    return { payloads, modelInterfaces, referencedModels, emitted, remaining };
}
//# sourceMappingURL=imported-event-payloads.js.map