import type { SanitizedConfig } from "payload";
import type { ITracer, ILogger } from "../instrumentation";
import type { IJobQueue } from "../jobs";
import type {
  EventBusProtocol,
  RealtimeBroadcasterProtocol,
  RealtimeRegistryProtocol,
} from "./bind-protocols";

/** Always-present fields. Feature binders rely on these unconditionally. */
type BindContextBase = {
  tracer: ITracer;
  logger: ILogger;
};

/**
 * Optional cross-cutting deps. Generics let the app aggregator narrow the
 * shape to full interfaces (`IEventBus`, `IRealtimeBroadcaster`, etc.); feature
 * binders see only the protocol surface, which is enough for the methods they
 * call. When an optional core package is absent the corresponding generic
 * defaults to its protocol type, and `ctx.bus` / `ctx.realtime` are undefined
 * at runtime.
 */
export type BindContext<
  Bus extends EventBusProtocol = EventBusProtocol,
  Realtime extends RealtimeBroadcasterProtocol = RealtimeBroadcasterProtocol,
  RealtimeReg extends RealtimeRegistryProtocol = RealtimeRegistryProtocol,
> = BindContextBase & {
  bus?: Bus;
  queue?: IJobQueue;
  realtime?: Realtime;
  realtimeRegistry?: RealtimeReg;
};

/** Production binders also receive the resolved Payload config. */
export type BindProductionContext<
  Bus extends EventBusProtocol = EventBusProtocol,
  Realtime extends RealtimeBroadcasterProtocol = RealtimeBroadcasterProtocol,
  RealtimeReg extends RealtimeRegistryProtocol = RealtimeRegistryProtocol,
> = BindContext<Bus, Realtime, RealtimeReg> & {
  config: SanitizedConfig;
};
