/**
 * Validation utilities for forms and data
 */

import { z } from 'zod';

// =============================================================================
// ZOD SCHEMAS - Centralized validation schemas for consistent validation
// =============================================================================

/**
 * Email validation schema using Zod
 * - Uses Zod's built-in email validator (RFC 5322 compliant)
 * - Trims whitespace before validation
 * - Provides consistent error messages in Spanish
 */
export const emailSchema = z
  .string()
  .trim()
  .min(1, 'El email es requerido')
  .email('Por favor, ingrese un email válido');

/**
 * Validates an email string using the centralized Zod schema
 * @param email - The email string to validate
 * @returns Object with isValid boolean and optional error message
 */
export const validateEmail = (email: string): { isValid: boolean; error?: string } => {
  const result = emailSchema.safeParse(email);
  if (result.success) {
    return { isValid: true };
  }
  return { isValid: false, error: result.error.errors[0]?.message };
};

// =============================================================================
// LEGACY VALIDATION FUNCTIONS - Kept for backward compatibility
// =============================================================================

// Email validation (legacy - use validateEmail or emailSchema instead)
export const isValidEmail = (email: string): boolean => {
  if (!email || typeof email !== 'string') {
    return false;
  }

  const result = emailSchema.safeParse(email);
  return result.success;
};

// Spanish phone number validation
export const isValidSpanishPhone = (phone: string): boolean => {
  if (!phone || typeof phone !== 'string') {
    return false;
  }

  // Remove all non-digit characters
  const digits = phone.replace(/\D/g, '');

  // Spanish mobile: 6/7/8/9 + 8 digits (9 total)
  // Spanish landline: 9 + 8 digits (9 total)
  // International: +34 + 9 digits (11 total with country code)
  const patterns = [
    /^[6789]\d{8}$/, // 9 digits starting with 6,7,8,9
    /^34[6789]\d{8}$/, // 34 + 9 digits
  ];

  return patterns.some(pattern => pattern.test(digits));
};

// Password strength validation
export interface PasswordValidation {
  isValid: boolean;
  score: number; // 0-4
  feedback: string[];
  requirements: {
    minLength: boolean;
    hasUppercase: boolean;
    hasLowercase: boolean;
    hasNumbers: boolean;
    hasSpecialChars: boolean;
    noCommonPatterns: boolean;
  };
}

export const validatePassword = (password: string): PasswordValidation => {
  if (!password || typeof password !== 'string') {
    return {
      isValid: false,
      score: 0,
      feedback: ['La contraseña es requerida'],
      requirements: {
        minLength: false,
        hasUppercase: false,
        hasLowercase: false,
        hasNumbers: false,
        hasSpecialChars: false,
        noCommonPatterns: false,
      },
    };
  }

  const requirements = {
    minLength: password.length >= 8,
    hasUppercase: /[A-Z]/.test(password),
    hasLowercase: /[a-z]/.test(password),
    hasNumbers: /\d/.test(password),
    hasSpecialChars: /[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(password),
    noCommonPatterns: !isCommonPassword(password),
  };

  const feedback: string[] = [];
  let score = 0;

  // Check requirements and provide feedback
  if (!requirements.minLength) {
    feedback.push('Debe tener al menos 8 caracteres');
  } else {
    score += 1;
  }

  if (!requirements.hasUppercase) {
    feedback.push('Debe incluir al menos una letra mayúscula');
  } else {
    score += 1;
  }

  if (!requirements.hasLowercase) {
    feedback.push('Debe incluir al menos una letra minúscula');
  } else {
    score += 0.5;
  }

  if (!requirements.hasNumbers) {
    feedback.push('Debe incluir al menos un número');
  } else {
    score += 1;
  }

  if (!requirements.hasSpecialChars) {
    feedback.push('Debe incluir al menos un carácter especial');
  } else {
    score += 1;
  }

  if (!requirements.noCommonPatterns) {
    feedback.push('No debe usar contraseñas comunes');
    score -= 1;
  } else {
    score += 0.5;
  }

  // Length bonus
  if (password.length >= 12) {
    score += 1;
  }

  score = Math.max(0, Math.min(4, score));
  const isValid = score >= 3 && Object.values(requirements).every(req => req);

  return {
    isValid,
    score,
    feedback: feedback.length > 0 ? feedback : ['Contraseña segura'],
    requirements,
  };
};

// Common passwords check
const isCommonPassword = (password: string): boolean => {
  const commonPasswords = [
    'password', '123456', '123456789', 'qwerty', 'abc123',
    'password123', '12345678', '111111', '1234567890',
    'letmein', 'welcome', 'monkey', 'dragon', 'pass',
    'master', 'hello', 'freedom', 'whatever', 'qazwsx',
    'trustno1', 'jordan23', 'harley', 'robert', 'matthew',
  ];

  return commonPasswords.includes(password.toLowerCase());
};

// URL validation
export const isValidUrl = (url: string): boolean => {
  if (!url || typeof url !== 'string') {
    return false;
  }

  try {
    new URL(url);
    return true;
  } catch {
    return false;
  }
};

// Spanish postal code validation
export const isValidSpanishPostalCode = (postalCode: string): boolean => {
  if (!postalCode || typeof postalCode !== 'string') {
    return false;
  }

  // Spanish postal codes: 5 digits, first two indicate province
  const regex = /^[0-5]\d{4}$/;
  return regex.test(postalCode.trim());
};

// VAT number validation (Spanish CIF/NIF)
export const isValidSpanishVAT = (vat: string): boolean => {
  if (!vat || typeof vat !== 'string') {
    return false;
  }

  const cleanVat = vat.replace(/\s/g, '').toUpperCase();

  // NIF format: 8 digits + 1 letter
  const nifRegex = /^\d{8}[A-Z]$/;
  if (nifRegex.test(cleanVat)) {
    return validateNIF(cleanVat);
  }

  // CIF format: 1 letter + 7 digits + 1 letter/digit
  const cifRegex = /^[ABCDEFGHJNPQRSUVW]\d{7}[A-J\d]$/;
  if (cifRegex.test(cleanVat)) {
    return validateCIF(cleanVat);
  }

  return false;
};

// NIF validation with check digit
const validateNIF = (nif: string): boolean => {
  const letters = 'TRWAGMYFPDXBNJZSQVHLCKE';
  const number = parseInt(nif.substring(0, 8), 10);
  const letter = nif.charAt(8);
  return letters.charAt(number % 23) === letter;
};

// CIF validation with check digit
const validateCIF = (cif: string): boolean => {
  const firstLetter = cif.charAt(0);
  const checkDigit = cif.charAt(8);
  const numbers = cif.substring(1, 8);

  let sum = 0;
  for (let i = 0; i < numbers.length; i++) {
    const digit = parseInt(numbers.charAt(i), 10);
    if (i % 2 === 0) {
      // Positions 0, 2, 4, 6
      const doubled = digit * 2;
      sum += doubled > 9 ? doubled - 9 : doubled;
    } else {
      // Positions 1, 3, 5
      sum += digit;
    }
  }

  const units = sum % 10;
  const controlNumber = units === 0 ? 0 : 10 - units;
  const controlLetter = 'JABCDEFGHI'.charAt(controlNumber);

  // Some CIF types use letter, others use digit
  if (['N', 'P', 'Q', 'R', 'S', 'W'].includes(firstLetter)) {
    return checkDigit === controlLetter;
  } else {
    return checkDigit === controlNumber.toString() || checkDigit === controlLetter;
  }
};

// Credit card validation (Luhn algorithm)
export const isValidCreditCard = (cardNumber: string): boolean => {
  if (!cardNumber || typeof cardNumber !== 'string') {
    return false;
  }

  const digits = cardNumber.replace(/\s/g, '').replace(/-/g, '');
  
  if (!/^\d+$/.test(digits) || digits.length < 13 || digits.length > 19) {
    return false;
  }

  // Luhn algorithm
  let sum = 0;
  let isEven = false;

  for (let i = digits.length - 1; i >= 0; i--) {
    let digit = parseInt(digits.charAt(i), 10);

    if (isEven) {
      digit *= 2;
      if (digit > 9) {
        digit -= 9;
      }
    }

    sum += digit;
    isEven = !isEven;
  }

  return sum % 10 === 0;
};

// Numeric validation
export const isNumeric = (value: any): boolean => {
  return !isNaN(value) && !isNaN(parseFloat(value));
};

// Positive number validation
export const isPositiveNumber = (value: any): boolean => {
  return isNumeric(value) && parseFloat(value) > 0;
};

// Integer validation
export const isInteger = (value: any): boolean => {
  return isNumeric(value) && Number.isInteger(parseFloat(value));
};

// Range validation
export const isInRange = (value: number, min: number, max: number): boolean => {
  return isNumeric(value) && value >= min && value <= max;
};

// Date validation
export const isValidDate = (dateString: string): boolean => {
  if (!dateString || typeof dateString !== 'string') {
    return false;
  }

  const date = new Date(dateString);
  return date instanceof Date && !isNaN(date.getTime());
};

// Future date validation
export const isFutureDate = (dateString: string): boolean => {
  if (!isValidDate(dateString)) {
    return false;
  }

  const date = new Date(dateString);
  const now = new Date();
  return date > now;
};

// Past date validation
export const isPastDate = (dateString: string): boolean => {
  if (!isValidDate(dateString)) {
    return false;
  }

  const date = new Date(dateString);
  const now = new Date();
  return date < now;
};

// Age validation (18+ years)
export const isValidAge = (birthDate: string): boolean => {
  if (!isValidDate(birthDate)) {
    return false;
  }

  const birth = new Date(birthDate);
  const now = new Date();
  const age = now.getFullYear() - birth.getFullYear();
  const monthDiff = now.getMonth() - birth.getMonth();
  
  if (monthDiff < 0 || (monthDiff === 0 && now.getDate() < birth.getDate())) {
    return age - 1 >= 18;
  }
  
  return age >= 18;
};

// Required field validation
export const isRequired = (value: any): boolean => {
  if (value === null || value === undefined) {
    return false;
  }

  if (typeof value === 'string') {
    return value.trim().length > 0;
  }

  if (Array.isArray(value)) {
    return value.length > 0;
  }

  return true;
};

// Minimum length validation
export const hasMinLength = (value: string, minLength: number): boolean => {
  if (!value || typeof value !== 'string') {
    return false;
  }

  return value.trim().length >= minLength;
};

// Maximum length validation
export const hasMaxLength = (value: string, maxLength: number): boolean => {
  if (!value || typeof value !== 'string') {
    return true; // Empty values are valid for max length
  }

  return value.trim().length <= maxLength;
};

// File validation
export interface FileValidationOptions {
  maxSize?: number; // in bytes
  allowedTypes?: string[];
  maxFiles?: number;
}

export const validateFiles = (
  files: FileList | File[],
  options: FileValidationOptions = {}
): { isValid: boolean; errors: string[] } => {
  const errors: string[] = [];
  const fileArray = Array.from(files);

  const {
    maxSize = 10 * 1024 * 1024, // 10MB default
    allowedTypes = [],
    maxFiles = 10,
  } = options;

  // Check number of files
  if (fileArray.length > maxFiles) {
    errors.push(`No puedes subir más de ${maxFiles} archivos`);
  }

  // Check each file
  fileArray.forEach((file, index) => {
    // Check file size
    if (file.size > maxSize) {
      errors.push(`El archivo "${file.name}" es demasiado grande. Máximo: ${formatFileSize(maxSize)}`);
    }

    // Check file type
    if (allowedTypes.length > 0 && !allowedTypes.includes(file.type)) {
      errors.push(`Tipo de archivo no permitido: "${file.name}". Tipos permitidos: ${allowedTypes.join(', ')}`);
    }
  });

  return {
    isValid: errors.length === 0,
    errors,
  };
};

// Format file size for error messages
const formatFileSize = (bytes: number): string => {
  if (bytes === 0) return '0 B';
  
  const k = 1024;
  const sizes = ['B', 'KB', 'MB', 'GB'];
  const i = Math.floor(Math.log(bytes) / Math.log(k));
  
  return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${sizes[i]}`;
};

// Validation helper for forms
export const createValidator = (rules: Record<string, (value: any) => boolean>) => {
  return (data: Record<string, any>): Record<string, string> => {
    const errors: Record<string, string> = {};

    Object.entries(rules).forEach(([field, validator]) => {
      const value = data[field];
      if (!validator(value)) {
        errors[field] = `${field} is invalid`;
      }
    });

    return errors;
  };
};

// Common validation patterns
export const ValidationPatterns = {
  email: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
  spanishPhone: /^[6789]\d{8}$/,
  spanishPostalCode: /^[0-5]\d{4}$/,
  strongPassword: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/,
  url: /^https?:\/\/([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/,
  alphanumeric: /^[a-zA-Z0-9]+$/,
  numbersOnly: /^\d+$/,
  lettersOnly: /^[a-zA-ZáéíóúüñÁÉÍÓÚÜÑ\s]+$/,
  noSpecialChars: /^[a-zA-Z0-9\s]+$/,
};