import { Criteria } from "@repo/rdx-criteria/server";
import { UniqueID } from "@repo/rdx-ddd";
import { Collection, Result } from "@repo/rdx-utils";
import { CustomerListDTO } from "../../infrastructure/mappers";
import { Customer } from "../aggregates";

/**
 * Interfaz del repositorio para el agregado `Customer`.
 * El escopado multitenant está representado por `companyId`.
 */
export interface ICustomerRepository {
  /**
   *
   * Crea un nuevo cliente
   *
   * @param customer - El cliente nuevo a guardar.
   * @param transaction - Transacción activa para la operación.
   * @returns Result<void, Error>
   */
  create(customer: Customer, transaction: unknown): Promise<Result<void, Error>>;

  /**
   * Actualiza un cliente existente.
   *
   * @param customer - El cliente a actualizar.
   * @param transaction - Transacción activa para la operación.
   * @returns Result<void, Error>
   */
  update(customer: Customer, transaction: unknown): Promise<Result<void, Error>>;

  /**
   * Comprueba si existe un Customer con un `id` dentro de una `company`.
   */
  existsByIdInCompany(
    companyId: UniqueID,
    id: UniqueID,
    transaction: unknown
  ): Promise<Result<boolean, Error>>;

  /**
   * Recupera un Customer por su ID y companyId.
   * Devuelve un `NotFoundError` si no se encuentra.
   */
  getByIdInCompany(
    companyId: UniqueID,
    id: UniqueID,
    transaction: unknown
  ): Promise<Result<Customer, Error>>;

  /**
   * Recupera múltiples customers dentro de una empresa
   * según un criterio dinámico (búsqueda, paginación, etc.).
   * El resultado está encapsulado en un objeto `Collection<T>`.
   */
  findByCriteriaInCompany(
    companyId: UniqueID,
    criteria: Criteria,
    transaction: unknown
  ): Promise<Result<Collection<CustomerListDTO>, Error>>;

  /**
   * Elimina un Customer por su ID, dentro de una empresa.
   * Retorna `void` si se elimina correctamente, o `NotFoundError` si no existía.
   *
   */
  deleteByIdInCompany(
    companyId: UniqueID,
    id: UniqueID,
    transaction: unknown
  ): Promise<Result<boolean, Error>>;
}
