import type { ObjectSchema } from "@wrnexus/validation";

/** Extract the validated value type from a `v.object(...)` schema. */
export type InferInput<S> = S extends ObjectSchema<infer T> ? T : never;

/**
 * One callable procedure on a service. `input` is validated on the callee
 * before the handler runs; `permission` is enforced there too.
 */
/** Structural shape of a validation schema, so ProcedureDef needs no generic. */
export interface InputSchema {
  parse(value: Record<string, unknown>): {
    ok: boolean;
    value: unknown;
    errors: Record<string, string>;
  };
}

export interface ProcedureDef<Input = unknown, Output = unknown> {
  input?: InputSchema;
  /** Permission the callee checks before invoking the handler. */
  permission?: string;
  /** Only idempotent procedures are ever retried. */
  idempotent?: boolean;
  /** Type-only markers; never present at runtime. */
  readonly __input?: Input;
  readonly __output?: Output;
}

/**
 * A procedure map with its element types erased. The `any` is deliberate and
 * confined to this alias: the phantom `__input`/`__output` markers make
 * ProcedureDef invariant, so no narrower erasure accepts a real contract.
 * (No eslint-disable needed — `no-explicit-any` is off repo-wide, and a
 * redundant directive is itself a lint warning.)
 */
export type AnyProcedures = Record<string, ProcedureDef<any, any>>;

export interface ServiceContract<Procedures extends AnyProcedures = AnyProcedures> {
  /** Stable service id, used in the mounted path. */
  name: string;
  procedures: Procedures;
}

export type InferProcedureInput<P> = P extends ProcedureDef<infer I, unknown> ? I : never;
export type InferProcedureOutput<P> = P extends ProcedureDef<unknown, infer O> ? O : never;

/** What a transport returns: either a value or a structured failure. */
export type ServiceResult<T = unknown> =
  { ok: true; value: T } | { ok: false; code: string; message: string; retryable: boolean };
