/**
 * Mawidi Demo Scheduler - Validation Utilities
 * Comprehensive validation functions for form data and user inputs
 */

import type {
  ValidationResult,
  FormErrors,
  UserInfo,
} from "../types/scheduler.types";
import { VALIDATION_RULES, UI_TEXT } from "../config/schedulerConfig";

/**
 * Validate email address (RFC 5322 compliant)
 *
 * @param email - Email address to validate
 * @returns Validation result
 */
export function validateEmail(email: string): ValidationResult {
  if (!email || email.trim().length === 0) {
    return {
      valid: false,
      error: "Email is required",
    };
  }

  const trimmedEmail = email.trim();

  if (!VALIDATION_RULES.email.pattern.test(trimmedEmail)) {
    return {
      valid: false,
      error: "Please enter a valid email address",
    };
  }

  return { valid: true };
}

/**
 * Validate phone number (international format)
 *
 * @param phone - Phone number to validate (optional field)
 * @returns Validation result
 */
export function validatePhoneNumber(phone?: string): ValidationResult {
  // Phone is optional for frontend validation
  if (!phone || phone.trim().length === 0) {
    return { valid: true };
  }

  const trimmedPhone = phone.trim();

  // Lenient pattern - allow optional + at start, digits, spaces, dashes, parentheses
  const phonePattern = /^[\d\s\-+()]*$/;
  if (!phonePattern.test(trimmedPhone)) {
    return {
      valid: false,
      error: "Phone number can only contain digits, spaces, +, -, and ()",
    };
  }

  // Count only digits for length validation
  const digitsOnly = trimmedPhone.replace(/\D/g, "");

  // Must have 6-15 digits (relaxed from 10 to accommodate country code + 6 digit minimum)
  if (digitsOnly.length < 6) {
    return {
      valid: false,
      error: `Phone number must be at least 6 digits`,
    };
  }

  if (digitsOnly.length > 15) {
    return {
      valid: false,
      error: `Phone number too long (max 15 digits)`,
    };
  }

  // Frontend validation passes - backend will normalize and validate
  return { valid: true };
}

/**
 * Validate name field
 *
 * @param name - Name to validate
 * @returns Validation result
 */
export function validateName(name: string): ValidationResult {
  if (!name || name.trim().length === 0) {
    return {
      valid: false,
      error: "Name is required",
    };
  }

  const trimmedName = name.trim();

  if (trimmedName.length < VALIDATION_RULES.name.minLength) {
    return {
      valid: false,
      error: `Name must be at least ${VALIDATION_RULES.name.minLength} characters`,
    };
  }

  if (trimmedName.length > VALIDATION_RULES.name.maxLength) {
    return {
      valid: false,
      error: `Name must be at most ${VALIDATION_RULES.name.maxLength} characters`,
    };
  }

  if (!VALIDATION_RULES.name.pattern.test(trimmedName)) {
    return {
      valid: false,
      error: "Name can only contain letters, spaces, hyphens, and apostrophes",
    };
  }

  return { valid: true };
}

/**
 * Validate message field
 *
 * @param message - Message to validate
 * @returns Validation result
 */
export function validateMessage(message: string): ValidationResult {
  if (!message || message.trim().length === 0) {
    return {
      valid: false,
      error: "Message is required",
    };
  }

  const trimmedMessage = message.trim();

  if (trimmedMessage.length < VALIDATION_RULES.message.minLength) {
    return {
      valid: false,
      error: `Message must be at least ${VALIDATION_RULES.message.minLength} characters`,
    };
  }

  if (trimmedMessage.length > VALIDATION_RULES.message.maxLength) {
    return {
      valid: false,
      error: `Message must be at most ${VALIDATION_RULES.message.maxLength} characters`,
    };
  }

  return { valid: true };
}

/**
 * Validate complete user info
 *
 * @param userInfo - User info object to validate
 * @param language - Language for error messages
 * @returns Form errors object
 */
export function validateUserInfo(
  userInfo: Partial<UserInfo>,
  language: "en" | "ar",
): FormErrors {
  const errors: FormErrors = {};
  const t = UI_TEXT[language].validation;

  // Validate name
  if (!userInfo.name) {
    errors.name = t.nameRequired;
  } else {
    const nameResult = validateName(userInfo.name);
    if (!nameResult.valid) {
      errors.name = nameResult.error;
    }
  }

  // Validate email
  if (!userInfo.email) {
    errors.email = t.emailRequired;
  } else {
    const emailResult = validateEmail(userInfo.email);
    if (!emailResult.valid) {
      errors.email = t.emailInvalid;
    }
  }

  // Validate phone (optional)
  if (userInfo.phone) {
    const phoneResult = validatePhoneNumber(userInfo.phone);
    if (!phoneResult.valid) {
      errors.phone = t.phoneInvalid;
    }
  }

  // Validate message
  if (!userInfo.message) {
    errors.message = t.messageRequired;
  } else {
    const messageResult = validateMessage(userInfo.message);
    if (!messageResult.valid) {
      errors.message = messageResult.error;
    }
  }

  return errors;
}

/**
 * Check if form errors object has any errors
 *
 * @param errors - Form errors object
 * @returns True if there are any errors
 */
export function hasErrors(errors: FormErrors): boolean {
  return Object.keys(errors).length > 0;
}

/**
 * Sanitize user input to prevent XSS attacks
 *
 * @param input - User input string
 * @returns Sanitized string
 */
export function sanitizeInput(input: string): string {
  if (!input) return "";

  // Don't trim here - allow spaces during input
  // Trimming happens during validation
  return input
    .replace(/[<>]/g, "") // Remove < and >
    .replace(/javascript:/gi, "") // Remove javascript: protocol
    .replace(/on\w+\s*=/gi, "") // Remove event handlers
    .substring(0, 1000); // Limit length
}

/**
 * Sanitize complete user info object
 *
 * @param userInfo - User info to sanitize
 * @returns Sanitized user info
 */
export function sanitizeUserInfo(
  userInfo: Partial<UserInfo>,
): Partial<UserInfo> {
  return {
    name: userInfo.name ? sanitizeInput(userInfo.name) : undefined,
    email: userInfo.email ? sanitizeInput(userInfo.email) : undefined,
    phone: userInfo.phone ? sanitizeInput(userInfo.phone) : undefined,
    message: userInfo.message ? sanitizeInput(userInfo.message) : undefined,
    timezone: userInfo.timezone || "UTC",
  };
}

/**
 * Validate booking data completeness
 *
 * @param data - Booking data to validate
 * @returns Validation result
 */
export function validateBookingData(data: {
  duration: number | null;
  date: Date | null;
  time: string | null;
  userInfo: UserInfo | null;
}): ValidationResult {
  if (!data.duration) {
    return {
      valid: false,
      error: "Please select a meeting duration",
    };
  }

  if (data.duration !== 30 && data.duration !== 60) {
    return {
      valid: false,
      error: "Invalid meeting duration",
    };
  }

  if (!data.date) {
    return {
      valid: false,
      error: "Please select a date",
    };
  }

  if (!data.time) {
    return {
      valid: false,
      error: "Please select a time slot",
    };
  }

  if (!data.userInfo) {
    return {
      valid: false,
      error: "Please provide your contact information",
    };
  }

  // Validate user info
  const userInfoErrors = validateUserInfo(data.userInfo, "en");
  if (hasErrors(userInfoErrors)) {
    return {
      valid: false,
      error: "Please fix the errors in your contact information",
    };
  }

  return { valid: true };
}

/**
 * Validate timezone string
 *
 * @param timezone - IANA timezone identifier
 * @returns Validation result
 */
export function validateTimezone(timezone: string): ValidationResult {
  if (!timezone || timezone.trim().length === 0) {
    return {
      valid: false,
      error: "Timezone is required",
    };
  }

  // Basic format check
  if (!timezone.includes("/")) {
    return {
      valid: false,
      error: "Invalid timezone format",
    };
  }

  return { valid: true };
}

/**
 * Validate date is within booking window
 *
 * @param date - Date to validate
 * @param minAdvanceHours - Minimum hours in advance
 * @param maxAdvanceDays - Maximum days in advance
 * @returns Validation result
 */
export function validateBookingDate(
  date: Date,
  minAdvanceHours: number,
  maxAdvanceDays: number,
): ValidationResult {
  const now = new Date();
  const minDate = new Date(now.getTime() + minAdvanceHours * 60 * 60 * 1000);
  const maxDate = new Date(
    now.getTime() + maxAdvanceDays * 24 * 60 * 60 * 1000,
  );

  if (date < minDate) {
    return {
      valid: false,
      error: `Please book at least ${minAdvanceHours} hours in advance`,
    };
  }

  if (date > maxDate) {
    return {
      valid: false,
      error: `Bookings can only be made up to ${maxAdvanceDays} days in advance`,
    };
  }

  return { valid: true };
}

/**
 * Validate time slot format (HH:mm)
 *
 * @param timeString - Time string to validate
 * @returns Validation result
 */
export function validateTimeFormat(timeString: string): ValidationResult {
  if (!timeString) {
    return {
      valid: false,
      error: "Time is required",
    };
  }

  const timePattern = /^([0-1][0-9]|2[0-3]):[0-5][0-9]$/;
  if (!timePattern.test(timeString)) {
    return {
      valid: false,
      error: "Invalid time format (must be HH:mm)",
    };
  }

  return { valid: true };
}

/**
 * Normalize email address (lowercase, trim)
 *
 * @param email - Email to normalize
 * @returns Normalized email
 */
export function normalizeEmail(email: string): string {
  return email.trim().toLowerCase();
}

/**
 * Normalize phone number (remove formatting, keep digits and +)
 *
 * @param phone - Phone number to normalize
 * @returns Normalized phone
 */
export function normalizePhoneNumber(phone: string): string {
  // Keep only digits, +, and spaces
  return phone.replace(/[^\d+\s]/g, "").trim();
}

/**
 * Check if string contains potentially dangerous content
 *
 * @param input - String to check
 * @returns True if potentially dangerous
 */
export function containsMaliciousContent(input: string): boolean {
  const dangerousPatterns = [
    /<script/i,
    /javascript:/i,
    /on\w+=/i,
    /<iframe/i,
    /eval\(/i,
    /expression\(/i,
  ];

  return dangerousPatterns.some((pattern) => pattern.test(input));
}

/**
 * Validate URL (for meeting links)
 *
 * @param url - URL to validate
 * @returns Validation result
 */
export function validateURL(url: string): ValidationResult {
  if (!url || url.trim().length === 0) {
    return {
      valid: false,
      error: "URL is required",
    };
  }

  try {
    const urlObj = new URL(url);

    // Only allow http and https protocols
    if (urlObj.protocol !== "http:" && urlObj.protocol !== "https:") {
      return {
        valid: false,
        error: "URL must use http or https protocol",
      };
    }

    return { valid: true };
  } catch {
    return {
      valid: false,
      error: "Invalid URL format",
    };
  }
}

/**
 * Rate limiting check (simple client-side implementation)
 *
 * @param key - Unique key for rate limit (e.g., 'booking_submission')
 * @param maxAttempts - Maximum attempts allowed
 * @param windowMs - Time window in milliseconds
 * @returns True if rate limit exceeded
 */
export function isRateLimited(
  key: string,
  maxAttempts: number,
  windowMs: number,
): boolean {
  const storageKey = `ratelimit_${key}`;
  const now = Date.now();

  try {
    const data = localStorage.getItem(storageKey);
    if (!data) {
      // First attempt
      localStorage.setItem(
        storageKey,
        JSON.stringify({ attempts: 1, firstAttempt: now }),
      );
      return false;
    }

    const { attempts, firstAttempt } = JSON.parse(data);

    // Check if window has expired
    if (now - firstAttempt > windowMs) {
      // Reset
      localStorage.setItem(
        storageKey,
        JSON.stringify({ attempts: 1, firstAttempt: now }),
      );
      return false;
    }

    // Increment attempts
    if (attempts >= maxAttempts) {
      return true; // Rate limited
    }

    localStorage.setItem(
      storageKey,
      JSON.stringify({ attempts: attempts + 1, firstAttempt }),
    );
    return false;
  } catch {
    // If localStorage fails, allow the action
    return false;
  }
}

/**
 * Clear rate limit for a key
 *
 * @param key - Rate limit key to clear
 */
export function clearRateLimit(key: string): void {
  const storageKey = `ratelimit_${key}`;
  try {
    localStorage.removeItem(storageKey);
  } catch {
    // Ignore errors
  }
}
