import type { AnySchemaModel, ZodSchemaModel } from '@contractspec/lib.schema';
import * as z from 'zod';
import type { EventSpec } from './events';
import type { AnyOperationSpec, EmitDecl, OperationSpec } from './operations/';
import { OperationSpecRegistry } from './operations/registry';
import type { ResourceRefDescriptor } from './resources';
import type { ContractSuccess } from './results';
import type { HandlerCtx } from './types';
/** Infer input/output types from a OperationSpec */
export type OperationSpecInput<Spec extends AnyOperationSpec> = Spec['io']['input'];
export type ZodOperationSpecInput<Spec extends AnyOperationSpec> = ZodSchemaModel<OperationSpecInput<Spec> extends null ? AnySchemaModel : NonNullable<OperationSpecInput<Spec>>>;
export type OperationSpecOutput<Spec extends AnyOperationSpec> = Spec['io']['output'];
type ResourceItem<O extends ResourceRefDescriptor<boolean>> = Record<O['varName'] extends string ? O['varName'] : 'id', string | number>;
type ResourceRefOut<O> = O extends ResourceRefDescriptor<boolean> ? O['many'] extends true ? ResourceItem<O>[] : ResourceItem<O> : never;
export type RuntimeSpecOutput<Spec extends AnyOperationSpec> = OperationSpecOutput<Spec> extends AnySchemaModel ? ZodSchemaModel<OperationSpecOutput<Spec>> : ResourceRefOut<OperationSpecOutput<Spec>>;
/** Handler signature derived from the Spec */
export type HandlerForOperationSpec<Spec extends AnyOperationSpec, AllowContractResult extends boolean = false> = (args: ZodOperationSpecInput<Spec>, ctx: HandlerCtx) => Promise<AllowContractResult extends true ? RuntimeSpecOutput<Spec> | ContractSuccess<unknown, string> : RuntimeSpecOutput<Spec>>;
export type HandlerForOperationSpecWithResult<Spec extends AnyOperationSpec> = (args: ZodOperationSpecInput<Spec>, ctx: HandlerCtx) => Promise<RuntimeSpecOutput<Spec> | ContractSuccess<unknown, string>>;
/** Typed event param from Spec.sideEffects.emits */
export type EventParam<S extends OperationSpec<AnySchemaModel, AnySchemaModel | ResourceRefDescriptor<boolean>>> = S extends {
    sideEffects?: {
        emits?: readonly (infer E)[];
    };
} ? E extends {
    key: string;
    version: string;
    payload: AnySchemaModel;
} ? {
    key: E['key'];
    version: E['version'];
    payload: z.infer<ReturnType<E['payload']['getZod']>>;
} : never : never;
/** Build a type union of allowed events for a spec */
type AllowedEventUnion<S extends OperationSpec<AnySchemaModel, AnySchemaModel | ResourceRefDescriptor<boolean>>> = S['sideEffects'] extends {
    emits: readonly EmitDecl[];
} ? {
    [K in keyof S['sideEffects']['emits']]: S['sideEffects']['emits'][K] extends {
        ref: EventSpec<infer P>;
    } ? {
        key: S['sideEffects']['emits'][K]['ref']['meta']['key'];
        version: S['sideEffects']['emits'][K]['ref']['meta']['version'];
        payload: z.infer<ReturnType<P['getZod']>>;
    } : S['sideEffects']['emits'][K] extends {
        key: infer N extends string;
        version: infer V extends string;
        payload: infer Q extends AnySchemaModel;
    } ? {
        key: N;
        version: V;
        payload: z.infer<ReturnType<Q['getZod']>>;
    } : never;
}[number] : never;
/** Typed emit for a given spec (validates at runtime through ctx.__emitGuard__). */
export declare function makeEmit<S extends AnyOperationSpec>(_spec: S, ctx: HandlerCtx): {
    /** Le plus sûr : typé via EventSpec (pas besoin de tuple dans le spec) */
    ref: <T extends AnySchemaModel>(ev: EventSpec<T>, payload: ZodSchemaModel<T>) => Promise<void>;
    /** Nom/version explicites (runtime-checked par la guard) */
    key: (key: string, version: string, payload: unknown) => Promise<void>;
    /** Compat : objet (bénéficie du typing si votre spec a un tuple `as const`) */
    object: (evt: AllowedEventUnion<S>) => Promise<void>;
};
/**
 * Register the Spec and bind the handler in one call, with full type inference.
 * Returns the registry for chaining.
 */
export declare function installOp<S extends AnyOperationSpec>(reg: OperationSpecRegistry, spec: S, handler: HandlerForOperationSpecWithResult<S>): OperationSpecRegistry;
/**
 * Curried variant if you prefer building a module installer.
 *   const install = op(BeginSignupSpec, handler);
 *   install(reg);
 */
export declare function op<S extends AnyOperationSpec>(spec: S, handler: HandlerForOperationSpecWithResult<AnyOperationSpec>): {
    spec: S;
    handler: HandlerForOperationSpecWithResult<AnyOperationSpec>;
    install: (reg: OperationSpecRegistry) => OperationSpecRegistry;
};
export {};
