import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';

/**
 * 🔐 CUSTOM VALIDATORS - PraFrota
 * 
 * Validadores customizados para formulários da aplicação
 */

/**
 * 🎯 Validador para confirmação de senha
 * Verifica se o campo de confirmação coincide com o campo de senha
 * 
 * @param passwordField Nome do campo de senha (padrão: 'password')
 * @returns ValidatorFn
 */
export function passwordMatchValidator(passwordField: string = 'password'): ValidatorFn {
  return (control: AbstractControl): ValidationErrors | null => {
    if (!control.parent) {
      return null;
    }

    const password = control.parent.get(passwordField);
    const passwordConfirmation = control;

    if (!password || !passwordConfirmation) {
      return null;
    }

    if (password.value !== passwordConfirmation.value) {
      return { passwordMatch: true };
    }

    return null;
  };
}

/**
 * 🎯 Validador de força de senha
 * Verifica se a senha atende aos critérios de segurança
 * 
 * @returns ValidatorFn
 */
export function passwordStrengthValidator(): ValidatorFn {
  return (control: AbstractControl): ValidationErrors | null => {
    const value = control.value;

    if (!value) {
      return null;
    }

    const hasNumber = /[0-9]/.test(value);
    const hasUpper = /[A-Z]/.test(value);
    const hasLower = /[a-z]/.test(value);
    const hasSpecial = /[@$!%*?&]/.test(value);
    const isValidLength = value.length >= 8;

    const passwordValid = hasNumber && hasUpper && hasLower && hasSpecial && isValidLength;

    if (!passwordValid) {
      const errors: any = {};
      
      if (!isValidLength) errors.minLength = true;
      if (!hasNumber) errors.requiresNumber = true;
      if (!hasUpper) errors.requiresUppercase = true;
      if (!hasLower) errors.requiresLowercase = true;
      if (!hasSpecial) errors.requiresSpecial = true;

      return { passwordStrength: errors };
    }

    return null;
  };
}

/**
 * 🎯 Validador de CPF
 * Verifica se o CPF é válido
 * 
 * @returns ValidatorFn
 */
export function cpfValidator(): ValidatorFn {
  return (control: AbstractControl): ValidationErrors | null => {
    const cpf = control.value;

    if (!cpf) {
      return null;
    }

    // Remove caracteres não numéricos
    const cleanCpf = cpf.replace(/\D/g, '');

    // Verifica se tem 11 dígitos
    if (cleanCpf.length !== 11) {
      return { cpf: true };
    }

    // Verifica se todos os dígitos são iguais
    if (/^(\d)\1{10}$/.test(cleanCpf)) {
      return { cpf: true };
    }

    // Validação do CPF
    let sum = 0;
    let remainder;

    // Primeiro dígito verificador
    for (let i = 1; i <= 9; i++) {
      sum += parseInt(cleanCpf.substring(i - 1, i)) * (11 - i);
    }
    remainder = (sum * 10) % 11;
    if (remainder === 10 || remainder === 11) remainder = 0;
    if (remainder !== parseInt(cleanCpf.substring(9, 10))) {
      return { cpf: true };
    }

    // Segundo dígito verificador
    sum = 0;
    for (let i = 1; i <= 10; i++) {
      sum += parseInt(cleanCpf.substring(i - 1, i)) * (12 - i);
    }
    remainder = (sum * 10) % 11;
    if (remainder === 10 || remainder === 11) remainder = 0;
    if (remainder !== parseInt(cleanCpf.substring(10, 11))) {
      return { cpf: true };
    }

    return null;
  };
}

/**
 * 🎯 Validador de CNPJ
 * Verifica se o CNPJ é válido
 * 
 * @returns ValidatorFn
 */
export function cnpjValidator(): ValidatorFn {
  return (control: AbstractControl): ValidationErrors | null => {
    const cnpj = control.value;

    if (!cnpj) {
      return null;
    }

    // Remove caracteres não numéricos
    const cleanCnpj = cnpj.replace(/\D/g, '');

    // Verifica se tem 14 dígitos
    if (cleanCnpj.length !== 14) {
      return { cnpj: true };
    }

    // Verifica se todos os dígitos são iguais
    if (/^(\d)\1{13}$/.test(cleanCnpj)) {
      return { cnpj: true };
    }

    // Validação do CNPJ
    let length = cleanCnpj.length - 2;
    let numbers = cleanCnpj.substring(0, length);
    const digits = cleanCnpj.substring(length);
    let sum = 0;
    let pos = length - 7;

    for (let i = length; i >= 1; i--) {
      sum += parseInt(numbers.charAt(length - i)) * pos--;
      if (pos < 2) pos = 9;
    }

    let result = sum % 11 < 2 ? 0 : 11 - (sum % 11);
    if (result !== parseInt(digits.charAt(0))) {
      return { cnpj: true };
    }

    length = length + 1;
    numbers = cleanCnpj.substring(0, length);
    sum = 0;
    pos = length - 7;

    for (let i = length; i >= 1; i--) {
      sum += parseInt(numbers.charAt(length - i)) * pos--;
      if (pos < 2) pos = 9;
    }

    result = sum % 11 < 2 ? 0 : 11 - (sum % 11);
    if (result !== parseInt(digits.charAt(1))) {
      return { cnpj: true };
    }

    return null;
  };
}

/**
 * 🎯 Validador de telefone brasileiro
 * Verifica se o telefone está no formato correto
 * 
 * @returns ValidatorFn
 */
export function phoneValidator(): ValidatorFn {
  return (control: AbstractControl): ValidationErrors | null => {
    const phone = control.value;

    if (!phone) {
      return null;
    }

    // Remove caracteres não numéricos
    const cleanPhone = phone.replace(/\D/g, '');

    // Verifica se tem 10 ou 11 dígitos (com DDD)
    if (cleanPhone.length < 10 || cleanPhone.length > 11) {
      return { phone: true };
    }

    // Verifica se o DDD é válido (11-99)
    const ddd = parseInt(cleanPhone.substring(0, 2));
    if (ddd < 11 || ddd > 99) {
      return { phone: true };
    }

    return null;
  };
}
