import { Collection, Result } from "@repo/rdx-utils";

/**
 *  Tipo para los parámetros que reciben los métodos de los mappers
 *  Es un objeto que puede contener cualquier cosa.
 */
export type MapperParamsType = Record<string, unknown>;

/**
 * 🧭 Mapper de Dominio (Persistencia ↔ Dominio/Agregado)
 * - Responsabilidad: transformar un registro de persistencia en un agregado de dominio y viceversa.
 * - No debe contener lógica de negocio; sólo construcción/serialización de objetos.
 */
export interface IDomainMapper<TPersistence, TDomain> {
  /**
   * Convierte un registro crudo de persistencia (ORM/row) en un agregado/entidad de dominio.
   * Debe devolver Result.fail(...) si la construcción del dominio no es posible/consistente.
   */
  mapToDomain(raw: TPersistence, params?: MapperParamsType): Result<TDomain, Error>;

  /**
   *  Convierte un agregado/entidad de dominio en un objeto de persistencia listo para el ORM.
   *  Debe devolver Result.fail(...) si hay incoherencias o datos no serializables.
   */
  mapToPersistence(domain: TDomain, params?: MapperParamsType): Result<TPersistence, Error>;
}

/**
 * 📦 Extensión opcional para operaciones en lote de mapeo de dominio.
 *    Útil para repos que recuperan múltiples filas y necesitan entregar colecciones de agregados.
 */
export interface IBulkDomainMapper<TPersistence, TDomain> {
  /**
   * Mapea múltiples registros crudos de persistencia a una Collection de agregados de dominio.
   */
  mapToDomainCollection(
    raws: TPersistence[],
    totalCount: number,
    params?: MapperParamsType
  ): Result<Collection<TDomain>, Error>;

  /**
   * Mapea múltiples agregados de dominio a un array de objetos de persistencia.
   */
  mapToPersistenceArray(
    domains: Collection<TDomain>,
    params?: MapperParamsType
  ): Result<TPersistence[], Error>;
}

/**
 * 🧩 Tipo para cuando se desea un mapper de dominio con soporte opcional de operaciones en lote.
 * Puedes implementar sólo IDomainMapper y añadir IBulkDomainMapper cuando lo necesites.
 */
export type DomainMapperWithBulk<TPersistence, TDomain> = IDomainMapper<TPersistence, TDomain> &
  Partial<IBulkDomainMapper<TPersistence, TDomain>>;

/**
 *
 * 👓 Mapper de Read Model (Persistencia ↔ DTO/Proyección de Lectura)
 * - Responsabilidad: transformar registros de persistencia en DTOs para lectura (listados, resúmenes, informes).
 * - No intenta reconstruir agregados ni validar value objects de dominio.
 **/
export interface IQueryMapperWithBulk<TPersistence, TDTO> {
  /**
   * Convierte un registro crudo en un DTO de lectura.
   */
  mapToDTO(raw: TPersistence, params?: MapperParamsType): Result<TDTO, Error>;

  /**
   * Convierte múltiples registros crudos en una Collection de DTOs de lectura.
   */
  mapToDTOCollection(
    raws: TPersistence[],
    totalCount: number,
    params?: MapperParamsType
  ): Result<Collection<TDTO>, Error>;
}
