import { DomainValidationError, ValidationErrorCollection } from "@repo/rdx-ddd";
import {
  ConnectionError,
  DatabaseError,
  ForeignKeyConstraintError,
  ValidationError as SequelizeValidationError,
  UniqueConstraintError,
} from "sequelize";
import { DuplicateEntityError, EntityNotFoundError } from "../../domain";
import { InfrastructureRepositoryError } from "../errors/infrastructure-repository-error";
import { InfrastructureUnavailableError } from "../errors/infrastructure-unavailable-error";

/**
 * Traduce errores específicos de Sequelize a errores de dominio/infraestructura
 * entendibles por el resto de capas.
 *
 * 👉 Este traductor pertenece a la infraestructura (persistencia)
 */
export function translateSequelizeError(err: unknown): Error {
  console.log(err);

  // 1) Duplicados (índices únicos)
  if (err instanceof UniqueConstraintError) {
    // Tomamos el primer detalle (puede haber varios)
    const detail = err.errors?.[0];
    const entity = detail?.instance?.constructor.name ?? "unknown_entity";
    const value = detail?.value ?? "unknown_value";
    const field = detail?.path ?? "unknown_field";

    // ⚠️ Si los nombres de campo son sensibles, normaliza/whitelistea antes de exponerlos a dominio
    return new DuplicateEntityError(entity, field, value, { cause: err });
  }

  // 2) Violación de FK → error de validación de dominio (referencia inválida)
  if (err instanceof ForeignKeyConstraintError) {
    // Sequelize expone `fields` (obj) y `index`. Extraemos el campo si está.
    const entity = err.index ?? "unknown_entity";
    const field = err.fields ? Object.keys(err.fields)[0] : "foreign_key";
    const value = err.fields ? Object.values(err.fields)[0] : "unknown_value";
    return new EntityNotFoundError(entity, field, value, { cause: err });
  }

  // 3) Validaciones de Sequelize (pueden venir varias)
  if (err instanceof SequelizeValidationError) {
    const details = (err.errors ?? []).map((e) => ({
      path: e.path ?? "unknown",
      message: e.message,
      // Algunas props útiles: e.validatorKey / e.validatorName
      // biome-ignore lint/suspicious/noExplicitAny: <explanation>
      rule: (e as any).validatorKey ?? undefined,
    }));

    // Si sólo hay 1, puedes preferir DomainValidationError
    if (details.length === 1) {
      const d = details[0];
      return DomainValidationError.invalidFormat(d.path, d.message, { cause: err });
    }

    return new ValidationErrorCollection("Invalid data provided", details, { cause: err });
  }

  // 4) Conectividad / indisponibilidad (transitorio)
  if (err instanceof ConnectionError) {
    return new InfrastructureUnavailableError("Database connection unavailable", { cause: err });
  }

  // 5) Otros errores de base de datos (no transitorios)
  if (err instanceof DatabaseError) {
    return new InfrastructureRepositoryError("Database error occurred", { cause: err });
  }

  // 6) Fallback: deja pasar si ya es un Error tipado de tu app, si no wrap
  if (err instanceof Error) return err;

  return new InfrastructureRepositoryError("Unknown persistence error", { cause: err as unknown });
}
