/**
 * Módulo de validación para respuestas de cuestionarios
 * Este módulo puede ser utilizado tanto en backend (NestJS) como en frontend (Angular, React, etc.)
 */

// Interfaz para el resultado de validación
export interface ResultadoValidacion {
  valido: boolean;
  mensaje: string;
}

// Clase base para todos los validadores
export abstract class Validador {
  abstract validar(valor: string): ResultadoValidacion;
}

// Clase para validar correos electrónicos
export class ValidadorCorreo extends Validador {
  validar(valor: string): ResultadoValidacion {
    if (!valor) {
      return {
        valido: false,
        mensaje: 'El correo electrónico es requerido',
      };
    }

    // Expresión regular para validar correos
    // Valida el formato básico de correos: usuario@dominio.extensión
    const regex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;

    if (!regex.test(valor)) {
      return {
        valido: false,
        mensaje: 'El formato del correo electrónico no es válido',
      };
    }

    // Para correos institucionales (opcional)
    if (this.validarDominioInstitucional) {
      const dominios = ['acatlan.unam.mx', 'unam.mx', 'comunidad.unam.mx'];
      const dominio = valor.split('@')[1];

      if (!dominios.includes(dominio)) {
        return {
          valido: false,
          mensaje:
            'Debe ser un correo institucional (@acatlan.unam.mx, @unam.mx, @comunidad.unam.mx)',
        };
      }
    }

    return {
      valido: true,
      mensaje: 'Correo electrónico válido',
    };
  }

  // Propiedad que permite configurar si se validan sólo correos institucionales
  constructor(public validarDominioInstitucional: boolean = false) {
    super();
  }
}

// Clase para validar números telefónicos
export class ValidadorTelefono extends Validador {
  validar(valor: string): ResultadoValidacion {
    if (!valor) {
      return {
        valido: false,
        mensaje: 'El número telefónico es requerido',
      };
    }

    // Eliminar espacios, guiones y paréntesis para la validación
    const numeroLimpio = valor.replace(/[\s\-()]/g, '');

    // Verificar que solo contenga dígitos
    if (!/^\d+$/.test(numeroLimpio)) {
      return {
        valido: false,
        mensaje: 'El número telefónico solo debe contener dígitos',
      };
    }

    // Verificar longitud (para México, 10 dígitos)
    if (numeroLimpio.length !== 10) {
      return {
        valido: false,
        mensaje: 'El número telefónico debe tener 10 dígitos',
      };
    }

    return {
      valido: true,
      mensaje: 'Número telefónico válido',
    };
  }
}

// Clase para validar nombres
export class ValidadorNombre extends Validador {
  validar(valor: string): ResultadoValidacion {
    const regex = new RegExp(
      '/^[A-Za-zÁÉÍÓÚáéíóúÑñ]+(?: [A-Za-zÁÉÍÓÚáéíóúÑñ]+)*$/'
    );
    if (!valor) {
      return {
        valido: false,
        mensaje: 'El nombre es requerido',
      };
    }

    // Verificar longitud mínima
    if (valor.trim().length < 2) {
      return {
        valido: false,
        mensaje: 'El nombre debe tener al menos 2 caracteres',
      };
    }

    // Verificar que solo contenga letras y espacios
    if (regex.test(valor)) {
      return {
        valido: false,
        mensaje: 'El nombre solo debe contener letras y espacios',
      };
    }

    return {
      valido: true,
      mensaje: 'Nombre válido',
    };
  }
}

// Clase para validar números enteros
export class ValidadorEntero extends Validador {
  constructor(
    private min: number = Number.MIN_SAFE_INTEGER,
    private max: number = Number.MAX_SAFE_INTEGER
  ) {
    super();
  }

  validar(valor: string): ResultadoValidacion {
    if (!valor) {
      return {
        valido: false,
        mensaje: 'El valor numérico es requerido',
      };
    }

    // Verificar que sea un número entero
    if (!/^-?\d+$/.test(valor)) {
      return {
        valido: false,
        mensaje: 'El valor debe ser un número entero',
      };
    }

    const numero = parseInt(valor, 10);

    // Verificar rango
    if (numero < this.min || numero > this.max) {
      return {
        valido: false,
        mensaje: `El valor debe estar entre ${this.min} y ${this.max}`,
      };
    }

    return {
      valido: true,
      mensaje: 'Número entero válido',
    };
  }
}

// Clase para validar números decimales
export class ValidadorDecimal extends Validador {
  constructor(
    private min: number = Number.MIN_SAFE_INTEGER,
    private max: number = Number.MAX_SAFE_INTEGER,
    private decimales: number = 2
  ) {
    super();
  }

  validar(valor: string): ResultadoValidacion {
    if (!valor) {
      return {
        valido: false,
        mensaje: 'El valor numérico es requerido',
      };
    }

    // Verificar que sea un número decimal válido
    if (!/^-?\d+(\.\d+)?$/.test(valor)) {
      return {
        valido: false,
        mensaje: 'El valor debe ser un número decimal válido',
      };
    }

    const numero = parseFloat(valor);

    // Verificar rango
    if (numero < this.min || numero > this.max) {
      return {
        valido: false,
        mensaje: `El valor debe estar entre ${this.min} y ${this.max}`,
      };
    }

    // Verificar precisión decimal
    const partes = valor.split('.');
    if (partes.length > 1 && partes[1].length > this.decimales) {
      return {
        valido: false,
        mensaje: `El valor debe tener máximo ${this.decimales} decimales`,
      };
    }

    return {
      valido: true,
      mensaje: 'Número decimal válido',
    };
  }
}

// Clase para validar cuentas de alumno (formato específico UNAM - 9 dígitos)
export class ValidadorCuentaAlumno extends Validador {
  validar(valor: string): ResultadoValidacion {
    if (!valor) {
      return {
        valido: false,
        mensaje: 'La cuenta de alumno es requerida',
      };
    }

    // Formato de cuenta UNAM: 9 dígitos para todos los alumnos
    if (!/^\d{9}$/.test(valor)) {
      return {
        valido: false,
        mensaje:
          'La cuenta de alumno debe tener exactamente 9 dígitos numéricos',
      };
    }

    return {
      valido: true,
      mensaje: 'Cuenta de alumno válida',
    };
  }
}

// Fábrica de validadores para crear el validador apropiado según el tipo
export class FabricaValidadores {
  static crear(tipo: string): Validador | null {
    switch (tipo?.toLowerCase()) {
      case 'correo':
        return new ValidadorCorreo();
      case 'correo_institucional':
        return new ValidadorCorreo(true);
      case 'telefono':
        return new ValidadorTelefono();
      case 'nombre':
        return new ValidadorNombre();
      case 'entero':
        return new ValidadorEntero();
      case 'decimal':
        return new ValidadorDecimal();
      case 'cuenta_alumno':
        return new ValidadorCuentaAlumno();
      default:
        return null;
    }
  }
}

// Función auxiliar para validar respuestas basada en el tipo de validación
export function validarRespuesta(
  respuesta: string,
  tipoValidacion: string
): ResultadoValidacion {
  const validador = FabricaValidadores.crear(tipoValidacion);

  if (!validador) {
    return {
      valido: true, // Si no hay validador, consideramos válida la respuesta
      mensaje: 'No se requiere validación específica',
    };
  }

  return validador.validar(respuesta);
}
