/**
 * ValidationErrorCollection
 *
 * Esta clase representa un error de validación que agrega múltiples detalles de errores
 * en un formato estructurado. Es útil para manejar múltiples errores de validación
 * en una sola respuesta, permitiendo a los clientes entender qué campos fallaron y por qué.
 *
 * Ejemplo de uso:
 *
 * const errors: ValidationErrorDetail[] = [
 *   { path: "lines[1].unitPrice.amount", message: "Amount must be a positive number" },
 *   { path: "lines[1].unitPrice.scale", message: "Scale must be a non-negative integer" },
 * ];
 * const validationError = new ValidationErrorCollection(message, errors);
 *
 */

import { DomainError } from "./domain-error";
import { DomainValidationError } from "./domain-validation-error";

export interface ValidationErrorDetail {
  /** Path del campo inválido, ej. "lines[1].unitPrice.amount" */
  path?: string;
  /** Mensaje legible del fallo */
  message: string;
  /** Valor inválido (no se debe exponer directamente en API pública si es sensible) */
  value?: unknown;
}

/**
 * Error de validación múltiple de dominio.
 * Permite agrupar varios fallos de validación en una única instancia.
 *
 * Ejemplo:
 * const errors: ValidationErrorDetail[] = [
 *   { path: "lines[1].unitPrice.amount", message: "Amount must be positive" },
 *   { path: "lines[1].unitPrice.scale", message: "Scale must be non-negative" },
 * ];
 * throw new ValidationErrorCollection(message, errors);
 */
export class ValidationErrorCollection extends DomainError {
  public readonly kind = "VALIDATION" as const;
  public readonly code = "MULTIPLE_VALIDATION_ERRORS" as const;
  public readonly details: ValidationErrorDetail[];

  constructor(
    message: string,
    details: ValidationErrorDetail[],
    options?: ErrorOptions & { metadata?: Record<string, unknown> }
  ) {
    super(message, "MULTIPLE_VALIDATION_ERRORS", {
      ...options,
      metadata: { ...(options?.metadata ?? {}), errors: details },
    });
    this.name = "ValidationErrorCollection";
    this.details = details;

    Object.setPrototypeOf(this, new.target.prototype);
    Object.freeze(this);
  }

  /** Crear a partir de varios DomainValidationError */
  static fromErrors(
    message: string,
    errors: DomainValidationError[],
    options?: ErrorOptions & { metadata?: Record<string, unknown> }
  ): ValidationErrorCollection {
    const details: ValidationErrorDetail[] = errors.map((e) => ({
      path: e.field,
      message: e.detail,
      value: (e as any).cause, // opcional: valor que provocó el error
    }));

    return new ValidationErrorCollection(message, details, options);
  }

  /** Serialización para Problem+JSON / logs */
  override toJSON() {
    const base = super.toJSON();
    return {
      ...base,
      kind: this.kind,
      details: this.details.map((d) => ({
        path: d.path,
        message: d.message,
      })),
    };
  }
}

/** Type guard */
export const isValidationErrorCollection = (e: unknown): e is ValidationErrorCollection =>
  e instanceof ValidationErrorCollection;
