/**
 * Interview Booking Validators
 *
 * Input validation for interview booking requests.
 * Validates date, time, timezone, and additional notes.
 *
 * @module lib/validators/interview-booking.validator
 */

import validator from 'validator';
import { sanitizeInput } from '@/lib/input-validation';

/**
 * Business hours configuration
 */
export const BUSINESS_HOURS = {
  START: 9, // 9 AM
  END: 17, // 5 PM
  TIMEZONE: 'Asia/Qatar',
} as const;

/**
 * Booking window configuration
 */
export const BOOKING_WINDOW = {
  MIN_DAYS_AHEAD: 1, // At least 1 day in future
  MAX_DAYS_AHEAD: 14, // Within 14 days
} as const;

/**
 * Validation result interface
 */
interface ValidationResult {
  valid: boolean;
  error?: string;
  sanitized?: string;
}

/**
 * Validate preferred interview date
 *
 * Rules:
 * - Must be valid ISO date
 * - Must be in future (at least 1 day ahead)
 * - Must be within 14 days
 * - Must not be weekend (Saturday/Sunday)
 *
 * @param dateString - ISO date string (YYYY-MM-DD)
 * @returns Validation result
 */
export function validatePreferredDate(dateString: string): ValidationResult {
  if (!dateString) {
    return { valid: false, error: 'Interview date is required' };
  }

  // Validate ISO date format
  if (!validator.isISO8601(dateString)) {
    return { valid: false, error: 'Invalid date format. Use YYYY-MM-DD' };
  }

  const sanitized = sanitizeInput(dateString);
  const date = new Date(sanitized);
  const now = new Date();

  // Reset time for comparison
  now.setHours(0, 0, 0, 0);
  date.setHours(0, 0, 0, 0);

  // Check if date is in past
  if (date < now) {
    return { valid: false, error: 'Interview date must be in the future' };
  }

  // Check minimum advance booking
  const minDate = new Date();
  minDate.setDate(minDate.getDate() + BOOKING_WINDOW.MIN_DAYS_AHEAD);
  minDate.setHours(0, 0, 0, 0);

  if (date < minDate) {
    return {
      valid: false,
      error: `Interview must be scheduled at least ${BOOKING_WINDOW.MIN_DAYS_AHEAD} day(s) in advance`,
    };
  }

  // Check maximum advance booking
  const maxDate = new Date();
  maxDate.setDate(maxDate.getDate() + BOOKING_WINDOW.MAX_DAYS_AHEAD);
  maxDate.setHours(0, 0, 0, 0);

  if (date > maxDate) {
    return {
      valid: false,
      error: `Interview date cannot be more than ${BOOKING_WINDOW.MAX_DAYS_AHEAD} days in the future`,
    };
  }

  // Check if weekend (Saturday = 6, Sunday = 0)
  const dayOfWeek = date.getDay();
  if (dayOfWeek === 0 || dayOfWeek === 6) {
    return {
      valid: false,
      error: 'Interviews cannot be scheduled on weekends. Please select a weekday.',
    };
  }

  return { valid: true, sanitized };
}

/**
 * Validate preferred interview time
 *
 * Rules:
 * - Must be in HH:MM format (24-hour)
 * - Must be within business hours (9 AM - 5 PM)
 * - Must be on 30-minute intervals
 *
 * @param timeString - Time string (HH:MM)
 * @returns Validation result
 */
export function validatePreferredTime(timeString: string): ValidationResult {
  if (!timeString) {
    return { valid: false, error: 'Interview time is required' };
  }

  const sanitized = sanitizeInput(timeString);

  // Validate HH:MM format (24-hour)
  if (!/^([01]\d|2[0-3]):([0-5]\d)$/.test(sanitized)) {
    return {
      valid: false,
      error: 'Invalid time format. Use HH:MM (24-hour format)',
    };
  }

  // Parse hour and minute
  const [hourStr, minuteStr] = sanitized.split(':');
  const hour = parseInt(hourStr, 10);
  const minute = parseInt(minuteStr, 10);

  // Check business hours
  if (hour < BUSINESS_HOURS.START || hour >= BUSINESS_HOURS.END) {
    return {
      valid: false,
      error: `Interview time must be between ${BUSINESS_HOURS.START}:00 and ${BUSINESS_HOURS.END}:00`,
    };
  }

  // Check 30-minute intervals
  if (minute !== 0 && minute !== 30) {
    return {
      valid: false,
      error: 'Interview time must be on 30-minute intervals (e.g., 10:00, 10:30)',
    };
  }

  return { valid: true, sanitized };
}

/**
 * Validate timezone
 *
 * Rules:
 * - Must be valid IANA timezone identifier
 * - Common GCC timezones supported
 *
 * @param timezone - IANA timezone string
 * @returns Validation result
 */
export function validateTimezone(timezone: string): ValidationResult {
  if (!timezone) {
    return { valid: false, error: 'Timezone is required' };
  }

  const sanitized = sanitizeInput(timezone);

  // List of supported timezones (GCC + common international)
  const SUPPORTED_TIMEZONES = [
    'Asia/Qatar',
    'Asia/Dubai',
    'Asia/Riyadh',
    'Asia/Kuwait',
    'Asia/Bahrain',
    'Asia/Muscat',
    'Europe/London',
    'America/New_York',
    'America/Los_Angeles',
    'Asia/Kolkata',
    'Asia/Singapore',
    'UTC',
  ];

  if (!SUPPORTED_TIMEZONES.includes(sanitized)) {
    return {
      valid: false,
      error: 'Invalid timezone. Please select a supported timezone.',
    };
  }

  return { valid: true, sanitized };
}

/**
 * Validate additional notes
 *
 * Rules:
 * - Optional field
 * - Maximum 500 characters
 * - Must be sanitized (XSS prevention)
 *
 * @param notes - Additional notes text
 * @returns Validation result
 */
export function validateAdditionalNotes(notes?: string): ValidationResult {
  if (!notes) {
    return { valid: true, sanitized: '' };
  }

  const sanitized = sanitizeInput(notes);

  // Check maximum length
  const MAX_LENGTH = 500;
  if (sanitized.length > MAX_LENGTH) {
    return {
      valid: false,
      error: `Additional notes cannot exceed ${MAX_LENGTH} characters`,
    };
  }

  return { valid: true, sanitized };
}

/**
 * Validate complete booking request
 *
 * Validates all fields in a booking request object.
 *
 * @param data - Booking request data
 * @returns Combined validation result
 */
export function validateBookingRequest(data: {
  token: string;
  preferredDate: string;
  preferredTime: string;
  timezone: string;
  additionalNotes?: string;
}): {
  valid: boolean;
  errors: Record<string, string>;
  sanitized?: {
    token: string;
    preferredDate: string;
    preferredTime: string;
    timezone: string;
    additionalNotes: string;
  };
} {
  const errors: Record<string, string> = {};

  // Validate token
  if (!data.token || typeof data.token !== 'string') {
    errors.token = 'Token is required';
  }

  // Validate date
  const dateResult = validatePreferredDate(data.preferredDate);
  if (!dateResult.valid) {
    errors.preferredDate = dateResult.error!;
  }

  // Validate time
  const timeResult = validatePreferredTime(data.preferredTime);
  if (!timeResult.valid) {
    errors.preferredTime = timeResult.error!;
  }

  // Validate timezone
  const timezoneResult = validateTimezone(data.timezone);
  if (!timezoneResult.valid) {
    errors.timezone = timezoneResult.error!;
  }

  // Validate notes (optional)
  const notesResult = validateAdditionalNotes(data.additionalNotes);
  if (!notesResult.valid) {
    errors.additionalNotes = notesResult.error!;
  }

  // Check if any errors
  if (Object.keys(errors).length > 0) {
    return { valid: false, errors };
  }

  // Return sanitized data
  return {
    valid: true,
    errors: {},
    sanitized: {
      token: sanitizeInput(data.token),
      preferredDate: dateResult.sanitized!,
      preferredTime: timeResult.sanitized!,
      timezone: timezoneResult.sanitized!,
      additionalNotes: notesResult.sanitized || '',
    },
  };
}
