/**
 * Validation Utilities - Core Module
 *
 * Framework-agnostic validation helper functions.
 * Can be used in any project (NestJS, Express, Frontend, etc.)
 *
 * @module @core/utils/validation
 * @version 1.0.0
 */

/**
 * Check if value is email
 */
export const isEmail = (email: string): boolean => {
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  return emailRegex.test(email);
};

/**
 * Check if value is UUID (v4)
 */
export const isUUID = (uuid: string): boolean => {
  const uuidRegex =
    /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
  return uuidRegex.test(uuid);
};

/**
 * Check if value is valid URL
 */
export const isURL = (url: string): boolean => {
  try {
    new URL(url);
    return true;
  } catch {
    return false;
  }
};

/**
 * Check if password is strong
 * Requirements: 8+ chars, 1 uppercase, 1 lowercase, 1 number, 1 special char
 */
export const isStrongPassword = (password: string): boolean => {
  const strongRegex =
    /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/;
  return strongRegex.test(password);
};

/**
 * Get password strength (0-4)
 * 0: Very weak, 1: Weak, 2: Fair, 3: Strong, 4: Very strong
 */
export const getPasswordStrength = (password: string): number => {
  let strength = 0;

  if (password.length >= 8) strength++;
  if (password.length >= 12) strength++;
  if (/[a-z]/.test(password) && /[A-Z]/.test(password)) strength++;
  if (/\d/.test(password)) strength++;
  if (/[@$!%*?&#^()_+=[\]{};':"\\|,.<>/?-]/.test(password)) strength++;

  return Math.min(strength, 4);
};

/**
 * Check if value is phone number (international format)
 */
export const isPhoneNumber = (phone: string): boolean => {
  const phoneRegex = /^\+?[1-9]\d{1,14}$/;
  return phoneRegex.test(phone.replace(/[\s\-()]/g, ''));
};

/**
 * Check if value is numeric
 */
export const isNumeric = (value: string): boolean => {
  return !isNaN(Number(value)) && !isNaN(parseFloat(value));
};

/**
 * Check if value is integer
 */
export const isInteger = (value: string | number): boolean => {
  const num = typeof value === 'string' ? parseFloat(value) : value;
  return Number.isInteger(num);
};

/**
 * Check if value is alphanumeric
 */
export const isAlphanumeric = (value: string): boolean => {
  const alphanumericRegex = /^[a-zA-Z0-9]+$/;
  return alphanumericRegex.test(value);
};

/**
 * Check if value is alphabetic only
 */
export const isAlphabetic = (value: string): boolean => {
  const alphabeticRegex = /^[a-zA-Z]+$/;
  return alphabeticRegex.test(value);
};

/**
 * Check if value is within range (inclusive)
 */
export const isInRange = (value: number, min: number, max: number): boolean => {
  return value >= min && value <= max;
};

/**
 * Check if array has minimum length
 */
export const hasMinLength = <T>(array: T[], minLength: number): boolean => {
  return array.length >= minLength;
};

/**
 * Check if array has maximum length
 */
export const hasMaxLength = <T>(array: T[], maxLength: number): boolean => {
  return array.length <= maxLength;
};

/**
 * Check if string has minimum length
 */
export const hasMinStringLength = (str: string, minLength: number): boolean => {
  return str.length >= minLength;
};

/**
 * Check if string has maximum length
 */
export const hasMaxStringLength = (str: string, maxLength: number): boolean => {
  return str.length <= maxLength;
};

/**
 * Check if value is valid JSON string
 */
export const isValidJSON = (value: string): boolean => {
  try {
    JSON.parse(value);
    return true;
  } catch {
    return false;
  }
};

/**
 * Check if value is positive number
 */
export const isPositive = (value: number): boolean => {
  return value > 0;
};

/**
 * Check if value is non-negative number
 */
export const isNonNegative = (value: number): boolean => {
  return value >= 0;
};

/**
 * Check if value is negative number
 */
export const isNegative = (value: number): boolean => {
  return value < 0;
};

/**
 * Check if string matches pattern
 */
export const matchesPattern = (value: string, pattern: RegExp): boolean => {
  return pattern.test(value);
};

/**
 * Validate required fields in object
 */
export const hasRequiredFields = <T extends object>(
  obj: T,
  requiredFields: (keyof T)[],
): boolean => {
  return requiredFields.every(
    (field) => obj[field] !== undefined && obj[field] !== null,
  );
};

/**
 * Check if value is valid credit card number (Luhn algorithm)
 */
export const isCreditCard = (cardNumber: string): boolean => {
  const sanitized = cardNumber.replace(/\D/g, '');
  if (sanitized.length < 13 || sanitized.length > 19) return false;

  let sum = 0;
  let isEven = false;

  for (let i = sanitized.length - 1; i >= 0; i--) {
    let digit = parseInt(sanitized[i], 10);

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

    sum += digit;
    isEven = !isEven;
  }

  return sum % 10 === 0;
};

/**
 * Check if value is valid IP address (v4)
 */
export const isIPv4 = (ip: string): boolean => {
  const ipv4Regex =
    /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
  return ipv4Regex.test(ip);
};

/**
 * Check if value is valid hex color
 */
export const isHexColor = (color: string): boolean => {
  const hexColorRegex = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/;
  return hexColorRegex.test(color);
};

/**
 * Check if value is valid slug
 */
export const isSlug = (slug: string): boolean => {
  const slugRegex = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
  return slugRegex.test(slug);
};

/**
 * Check if value is valid username
 * Requirements: 3-30 chars, alphanumeric + underscore, starts with letter
 */
export const isValidUsername = (username: string): boolean => {
  const usernameRegex = /^[a-zA-Z][a-zA-Z0-9_]{2,29}$/;
  return usernameRegex.test(username);
};

/**
 * Check if object is empty
 */
export const isEmptyObject = (obj: object): boolean => {
  return Object.keys(obj).length === 0;
};

/**
 * Check if array is empty
 */
export const isEmptyArray = <T>(arr: T[]): boolean => {
  return arr.length === 0;
};

/**
 * Check if value is null or undefined
 */
export const isNullOrUndefined = (value: unknown): value is null | undefined => {
  return value === null || value === undefined;
};

/**
 * Check if value is defined (not null and not undefined)
 */
export const isDefined = <T>(value: T | null | undefined): value is T => {
  return value !== null && value !== undefined;
};

/**
 * Validate Mexican RFC (tax ID)
 */
export const isMexicanRFC = (rfc: string): boolean => {
  const rfcRegex =
    /^([A-ZÑ&]{3,4})(\d{2})(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])([A-Z\d]{2})([A\d])$/;
  return rfcRegex.test(rfc.toUpperCase());
};

/**
 * Validate Mexican CURP
 */
export const isMexicanCURP = (curp: string): boolean => {
  const curpRegex =
    /^[A-Z]{4}\d{6}[HM][A-Z]{5}[A-Z\d]\d$/;
  return curpRegex.test(curp.toUpperCase());
};

/**
 * Validation result type
 */
export interface ValidationResult {
  isValid: boolean;
  errors: string[];
}

/**
 * Create a validator chain
 */
export const createValidator = <T>(value: T): {
  validate: (condition: boolean, errorMessage: string) => ReturnType<typeof createValidator<T>>;
  result: () => ValidationResult;
} => {
  const errors: string[] = [];

  const validator = {
    validate: (condition: boolean, errorMessage: string) => {
      if (!condition) {
        errors.push(errorMessage);
      }
      return validator;
    },
    result: (): ValidationResult => ({
      isValid: errors.length === 0,
      errors,
    }),
  };

  return validator;
};
