import { IPresenter } from "./presenter.interface";

/**
 * 🔑 Claves de proyección comunes para seleccionar presenters
 */
export type PresenterKey = {
  resource: string;
  projection: "FULL" | "LIST" | "REPORT" | (string & {});
  format?: "JSON" | "HTML" | "PDF" | "CSV" | (string & {});
  version?: number; // 1 | 2
  locale?: string; // es | en | fr
};

/**
 * Ejemplo de uso:
 *
 * const registry = new InMemoryPresenterRegistry();
 *
 * // Registro
 * registry.register(
 *   { resource: "customer-invoice", projection: "detail", format: "json", version: 1 },
 *   new CustomerInvoiceDetailPresenter()
 * );
 *
 * registry.register(
 *   { resource: "customer-invoice", projection: "detail", format: "pdf", version: 1 },
 *   new CustomerInvoicePdfPresenter()
 * );
 *
 * // Resolución
 * const presenterOrNone = registry.resolve({
 *   resource: "customer-invoice",
 *   projection: "detail",
 *   format: "pdf",
 * });
 *
 * presenterOrNone.map(async (presenter) => {
 *    const output = await (presenter as IAsyncPresenter<any, any>).toOutput(invoice);
 *   console.log("PDF generado:", output);
 * });
 *
 **/

export interface IPresenterRegistry {
  /**
   * Obtiene un mapper de dominio por clave de proyección.
   */
  getPresenter<TSource = unknown, TOutput = unknown>(
    key: PresenterKey
  ): IPresenter<TSource, TOutput>;

  /**
   * Registra un mapper de dominio bajo una clave de proyección.
   */
  registerPresenter<TSource = unknown, TOutput = unknown>(
    key: PresenterKey,
    presenter: IPresenter<TSource, TOutput>
  ): this;

  registerPresenters(
    presenters: Array<{ key: PresenterKey; presenter: IPresenter<unknown, unknown> }>
  ): this;
}
