/**
 * Imported-operation signature emission — V2 Phase 3, Round 2 (TODO #81).
 *
 * The sibling of `imported-model-types.ts` for the SERVICE/operation story.
 * When a consumer `import:`s dotted operation selects (`PaymentService.processPayment`)
 * from a provider library, the emitted client previously used a placeholder
 * `(...args: unknown[]) => Promise<unknown>` signature. This module parses the
 * fetched/realized provider `.specly` and derives a REAL, typed signature per
 * selected operation — `processPayment(input: { orderId: string; amount: Money }):
 * Promise<string>` — from the operation's `parameters` + `returns`.
 *
 * Type tokens that name a MODEL exported by the same provider (e.g. `Money`,
 * `Order`) are referenced by interface name and returned in `referencedModels`
 * so the caller can emit those interfaces alongside (reusing
 * `extractImportedModelInterfaces`'s `emitInterface`). Primitive tokens map via
 * the shared `mapAttrType`.
 *
 * SCOPE (the #81 boundary): this produces real *signatures* (type-safe surface).
 * The client *body* for a registry source still throws at runtime — actually
 * CALLING a remote operation needs the provider's transport/deployment
 * coordinates (a per-topology concern), which is separate, larger work.
 */
import * as yaml from 'js-yaml';
import { parseAttr, mapAttrType, isRequired, collectModels, emitInterface, } from './imported-model-types.js';
/**
 * Collect every operation across the provider spec, keyed `<Owner>.<op>` —
 * matching the dotted-select form. Owners: services (`operations`) and
 * controllers (`cured` CURVED ops + custom `actions` + any `operations`).
 */
function collectOperations(parsed) {
    const ops = new Map();
    const components = parsed?.components;
    if (!components || typeof components !== 'object')
        return ops;
    const addBucket = (owner, bucket) => {
        if (!bucket || typeof bucket !== 'object')
            return;
        for (const [op, def] of Object.entries(bucket)) {
            ops.set(`${owner}.${op}`, (def ?? {}));
        }
    };
    for (const comp of Object.values(components)) {
        const services = comp?.services;
        if (services && typeof services === 'object') {
            for (const [svc, sdef] of Object.entries(services)) {
                addBucket(svc, sdef?.operations);
            }
        }
        const controllers = comp?.controllers;
        if (controllers && typeof controllers === 'object') {
            for (const [ctrl, cdef] of Object.entries(controllers)) {
                addBucket(ctrl, cdef?.cured);
                addBucket(ctrl, cdef?.actions);
                addBucket(ctrl, cdef?.operations);
            }
        }
    }
    return ops;
}
/** Map a param/return type token to TS, referencing provider models by name. */
function mapTypeModelAware(token, modelNames, referenced) {
    const p = parseAttr(token);
    if (p.base && modelNames.has(p.base)) {
        referenced.add(p.base);
        return p.isArray ? `${p.base}[]` : p.base;
    }
    return mapAttrType(token);
}
/** Build the `input: { ... }` parameter object type for an operation (or '' if none). */
function buildParamsType(params, modelNames, referenced) {
    if (!params || typeof params !== 'object')
        return '';
    const fields = Object.entries(params).map(([name, t]) => {
        const optional = isRequired(t) ? '' : '?';
        return `${name}${optional}: ${mapTypeModelAware(t, modelNames, referenced)}`;
    });
    return fields.length ? `input: { ${fields.join('; ')} }` : '';
}
/**
 * Parse a provider `.specly` + derive real typed signatures for the selected
 * dotted operations. Non-dotted entries and unresolved ops go to `remaining`
 * so the caller keeps prior behaviour for them.
 */
export function extractImportedOperationSignatures(specContent, dottedEntries) {
    let parsed;
    try {
        parsed = yaml.load(specContent);
    }
    catch {
        return { signatures: [], operations: [], modelInterfaces: [], referencedModels: [], emitted: [], remaining: [...dottedEntries] };
    }
    const ops = collectOperations(parsed);
    const models = collectModels(parsed);
    const modelNames = new Set(models.keys());
    const referenced = new Set();
    const signatures = [];
    const operations = [];
    const emitted = [];
    const remaining = [];
    for (const entry of dottedEntries) {
        if (!entry.includes('.')) {
            remaining.push(entry);
            continue;
        }
        const def = ops.get(entry);
        if (!def) {
            remaining.push(entry);
            continue;
        }
        const tail = entry.slice(entry.indexOf('.') + 1);
        const paramType = buildParamsType(def.parameters, modelNames, referenced);
        const returnType = def.returns != null && String(def.returns).trim() !== ''
            ? mapTypeModelAware(def.returns, modelNames, referenced)
            : 'void';
        signatures.push(`  /** ${entry} — imported operation (real signature, Round 2). */`);
        signatures.push(`  ${tail}(${paramType}): Promise<${returnType}>;`);
        operations.push({ entry, tail, paramType, returnType });
        emitted.push(entry);
    }
    const referencedModels = Array.from(referenced).filter((n) => models.has(n));
    const modelInterfaces = referencedModels.map((n) => emitInterface(n, models.get(n)));
    return { signatures, operations, modelInterfaces, referencedModels, emitted, remaining };
}
//# sourceMappingURL=imported-operation-signatures.js.map