/**
 * Validation Utilities for Demo Bookings
 *
 * This module provides validation functions for demo booking data.
 * Validates user input, request bodies, and data integrity.
 *
 * @module lib/staff-dashboard/demo-bookings/validators
 */

import type { DemoBookingUpdateRequest, DemoBookingFilters } from './types';
import { BOOKING_STATUSES, DATE_RANGES } from './constants';

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

/**
 * Validate booking ID format
 *
 * Ensures booking ID is a non-empty string with valid format.
 *
 * @param bookingId - Booking ID to validate
 * @returns True if valid, false otherwise
 *
 * @example
 * if (!isValidBookingId(id)) {
 *   return error('Invalid booking ID');
 * }
 */
export function isValidBookingId(bookingId: unknown): bookingId is string {
  return typeof bookingId === 'string' && bookingId.trim().length > 0;
}

/**
 * Validate booking status value
 *
 * Ensures status is one of the allowed values.
 *
 * @param status - Status value to validate
 * @returns True if valid status
 */
export function isValidBookingStatus(
  status: unknown
): status is 'pending' | 'confirmed' | 'cancelled' {
  return typeof status === 'string' && BOOKING_STATUSES.includes(status as any);
}

/**
 * Validate date range value
 *
 * Ensures date range is one of the allowed values.
 *
 * @param dateRange - Date range value to validate
 * @returns True if valid date range
 */
export function isValidDateRange(
  dateRange: unknown
): dateRange is 'all' | 'today' | 'week' | 'month' {
  return typeof dateRange === 'string' && DATE_RANGES.includes(dateRange as any);
}

/**
 * Validate meeting link URL
 *
 * Ensures meeting link is a valid URL for video conferencing.
 *
 * @param url - Meeting link to validate
 * @returns True if valid URL
 *
 * @example
 * if (meetingLink && !isValidMeetingLink(meetingLink)) {
 *   return error('Invalid meeting link URL');
 * }
 */
export function isValidMeetingLink(url: unknown): url is string {
  if (typeof url !== 'string') return false;
  if (url.trim().length === 0) return false;

  try {
    const parsed = new URL(url);
    // Must be http or https
    return parsed.protocol === 'http:' || parsed.protocol === 'https:';
  } catch {
    return false;
  }
}

/**
 * Validate update request body
 *
 * Validates the complete update request ensuring:
 * - Booking ID is present and valid
 * - At least one field is being updated
 * - All provided fields have valid values
 *
 * @param body - Request body to validate
 * @returns Validation result with errors if any
 *
 * @example
 * const validation = validateUpdateRequest(req.body);
 * if (!validation.valid) {
 *   return res.status(400).json({ errors: validation.errors });
 * }
 */
export function validateUpdateRequest(body: unknown): ValidationResult {
  const errors: string[] = [];

  // Check if body is an object
  if (!body || typeof body !== 'object') {
    return { valid: false, errors: ['Request body must be an object'] };
  }

  const request = body as Partial<DemoBookingUpdateRequest>;

  // Validate booking ID (required)
  if (!request.bookingId) {
    errors.push('Booking ID is required');
  } else if (!isValidBookingId(request.bookingId)) {
    errors.push('Invalid booking ID format');
  }

  // Check at least one field is being updated
  const hasUpdate =
    request.status !== undefined ||
    request.meetingLink !== undefined ||
    request.internalNotes !== undefined;

  if (!hasUpdate) {
    errors.push('At least one field must be updated');
  }

  // Validate status if provided
  if (request.status !== undefined && !isValidBookingStatus(request.status)) {
    errors.push(`Invalid status. Must be one of: ${BOOKING_STATUSES.join(', ')}`);
  }

  // Validate meeting link if provided
  if (request.meetingLink !== undefined && request.meetingLink !== null) {
    if (typeof request.meetingLink === 'string' && request.meetingLink.trim().length > 0) {
      if (!isValidMeetingLink(request.meetingLink)) {
        errors.push('Invalid meeting link URL');
      }
    }
  }

  // Validate internal notes if provided
  if (request.internalNotes !== undefined && request.internalNotes !== null) {
    if (typeof request.internalNotes !== 'string') {
      errors.push('Internal notes must be a string');
    } else if (request.internalNotes.length > 5000) {
      errors.push('Internal notes too long (max 5000 characters)');
    }
  }

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

/**
 * Validate filter parameters
 *
 * Validates filter object from query parameters.
 *
 * @param filters - Filters to validate
 * @returns Validation result
 *
 * @example
 * const validation = validateFilters(req.query);
 * if (!validation.valid) {
 *   return res.status(400).json({ errors: validation.errors });
 * }
 */
export function validateFilters(filters: unknown): ValidationResult {
  const errors: string[] = [];

  if (!filters || typeof filters !== 'object') {
    return { valid: true, errors: [] }; // Filters are optional
  }

  const f = filters as Partial<DemoBookingFilters>;

  // Validate status
  if (f.status !== undefined && f.status !== 'all') {
    if (!isValidBookingStatus(f.status)) {
      errors.push(`Invalid status filter. Must be one of: all, ${BOOKING_STATUSES.join(', ')}`);
    }
  }

  // Validate date range
  if (f.dateRange !== undefined && !isValidDateRange(f.dateRange)) {
    errors.push(`Invalid date range. Must be one of: ${DATE_RANGES.join(', ')}`);
  }

  // Validate search term
  if (f.search !== undefined) {
    if (typeof f.search !== 'string') {
      errors.push('Search term must be a string');
    } else if (f.search.length > 200) {
      errors.push('Search term too long (max 200 characters)');
    }
  }

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

/**
 * Sanitize and validate search input
 *
 * Prevents injection attacks and validates search term format.
 *
 * @param search - Raw search input from user
 * @returns Sanitized search term or null if invalid
 *
 * @example
 * const safe = sanitizeSearch(userInput);
 * if (safe) {
 *   // Use in query
 * }
 */
export function sanitizeSearch(search: unknown): string | null {
  if (typeof search !== 'string') return null;

  const trimmed = search.trim();
  if (trimmed.length === 0) return null;
  if (trimmed.length > 200) return null;

  // Remove potentially dangerous characters but keep Arabic
  const sanitized = trimmed.replace(/[^\w\s@.\-_\u0600-\u06FF]/g, '');

  return sanitized.length > 0 ? sanitized : null;
}
