/**
 * Contact Form Sanitization Module
 *
 * Handles sanitization of user-submitted contact form data.
 * Prevents XSS attacks and ensures data integrity.
 *
 * @module lib/sanitizers/contact.sanitizer
 */

import DOMPurify from 'isomorphic-dompurify';
import validator from 'validator';
import type { ContactFormData, SanitizedContactData } from '../types/contact.types';

/**
 * DOMPurify configuration for contact form fields
 * Strips all HTML tags to prevent XSS attacks
 */
const SANITIZE_CONFIG = {
  ALLOWED_TAGS: [] as string[], // No HTML allowed
  ALLOWED_ATTR: [] as string[], // No attributes allowed
  KEEP_CONTENT: true, // Keep text content
};

/**
 * Sanitize a text input to remove any potentially dangerous content
 *
 * @param input - Raw text input from user
 * @returns Sanitized text safe for database storage
 *
 * @example
 * ```typescript
 * const safe = sanitizeText('<script>alert("xss")</script>John');
 * // Returns: 'John' (script tags removed)
 * ```
 */
export function sanitizeText(input: string): string {
  if (!input) return '';
  return DOMPurify.sanitize(input, SANITIZE_CONFIG).trim();
}

/**
 * Sanitize and normalize an email address
 *
 * Converts to lowercase and applies standard normalization rules
 *
 * @param email - Raw email address
 * @returns Normalized email address or original if normalization fails
 *
 * @example
 * ```typescript
 * const email = sanitizeEmail('Test.User+Tag@Example.COM');
 * // Returns: 'test.user@example.com'
 * ```
 */
export function sanitizeEmail(email: string): string {
  if (!email) return '';

  // Normalize email (removes dots in Gmail, lowercase, etc.)
  const normalized = validator.normalizeEmail(email, {
    gmail_remove_dots: false, // Keep dots in Gmail addresses
    gmail_remove_subaddress: false, // Keep + addresses
    outlookdotcom_remove_subaddress: false,
    yahoo_remove_subaddress: false,
    icloud_remove_subaddress: false,
  });

  return normalized || email.toLowerCase().trim();
}

/**
 * Sanitize a phone number
 *
 * Removes potentially dangerous characters while preserving valid phone characters
 *
 * @param phone - Raw phone number
 * @returns Sanitized phone number
 *
 * @example
 * ```typescript
 * const phone = sanitizePhone('+974 <script>alert(1)</script> 1234-5678');
 * // Returns: '+974 1234-5678'
 * ```
 */
export function sanitizePhone(phone: string): string {
  if (!phone) return '';

  // Allow only numbers, spaces, dashes, parentheses, and + sign
  const sanitized = phone.replace(/[^0-9\s\-\(\)\+]/g, '').trim();

  return sanitized;
}

/**
 * Sanitize company name
 *
 * @param company - Raw company name
 * @returns Sanitized company name or null if empty
 */
export function sanitizeCompany(company: string | undefined): string | null {
  if (!company || company.trim().length === 0) return null;
  return sanitizeText(company);
}

/**
 * Sanitize message content
 *
 * Removes HTML but preserves line breaks and basic formatting
 *
 * @param message - Raw message content
 * @returns Sanitized message
 *
 * @example
 * ```typescript
 * const msg = sanitizeMessage('Hello\n<b>World</b>');
 * // Returns: 'Hello\nWorld' (preserves newlines, removes HTML)
 * ```
 */
export function sanitizeMessage(message: string): string {
  if (!message) return '';

  // Sanitize HTML but keep newlines
  const sanitized = DOMPurify.sanitize(message, {
    ...SANITIZE_CONFIG,
    RETURN_DOM: false,
    RETURN_DOM_FRAGMENT: false,
  });

  return sanitized.trim();
}

/**
 * Sanitize all contact form data
 *
 * Main sanitization function that processes all fields at once.
 * Use this in the API route after validation.
 *
 * @param data - Raw contact form data (already validated)
 * @returns Fully sanitized contact data safe for database storage
 *
 * @example
 * ```typescript
 * // After validation passes
 * const sanitized = sanitizeContactData(rawData);
 * await saveContactToBoth(sanitized);
 * ```
 */
export function sanitizeContactData(
  data: ContactFormData
): SanitizedContactData {
  return {
    name: sanitizeText(data.name),
    email: sanitizeEmail(data.email),
    phone: sanitizePhone(data.phone || ''),
    company: sanitizeCompany(data.company),
    topic: sanitizeText(data.topic),
    message: sanitizeMessage(data.message),
    preferredLanguage: data.preferredLanguage,
    consentGiven: data.consentGiven,
  };
}

/**
 * Check if text contains potential XSS patterns
 *
 * Useful for additional security screening before sanitization
 *
 * @param text - Text to check
 * @returns True if suspicious patterns detected
 *
 * @example
 * ```typescript
 * if (containsXSSPatterns(userInput)) {
 *   logger.warn('Potential XSS attempt detected');
 * }
 * ```
 */
export function containsXSSPatterns(text: string): boolean {
  if (!text) return false;

  const xssPatterns = [
    /<script/i,
    /javascript:/i,
    /on\w+\s*=/i, // onclick=, onerror=, etc.
    /<iframe/i,
    /<embed/i,
    /<object/i,
    /eval\(/i,
    /expression\(/i,
  ];

  return xssPatterns.some(pattern => pattern.test(text));
}

/**
 * Sanitize and validate filename
 *
 * Used for file attachment processing
 *
 * @param filename - Original filename
 * @returns Sanitized filename safe for storage
 *
 * @example
 * ```typescript
 * const safe = sanitizeFilename('../../../etc/passwd.txt');
 * // Returns: 'passwd.txt'
 * ```
 */
export function sanitizeFilename(filename: string): string {
  if (!filename) return 'unnamed';

  // Remove path traversal attempts
  let safe = filename.replace(/\.\./g, '');

  // Remove special characters except dot, dash, underscore
  safe = safe.replace(/[^a-zA-Z0-9.\-_]/g, '_');

  // Limit length
  if (safe.length > 255) {
    const ext = safe.substring(safe.lastIndexOf('.'));
    safe = safe.substring(0, 250 - ext.length) + ext;
  }

  return safe;
}

/**
 * Sanitize metadata object
 *
 * Recursively sanitizes object values to prevent injection
 *
 * @param obj - Object with potentially unsafe values
 * @returns Sanitized object
 */
export function sanitizeMetadata(obj: Record<string, any>): Record<string, any> {
  const sanitized: Record<string, any> = {};

  for (const [key, value] of Object.entries(obj)) {
    if (typeof value === 'string') {
      sanitized[key] = sanitizeText(value);
    } else if (typeof value === 'number' || typeof value === 'boolean') {
      sanitized[key] = value;
    } else if (value === null || value === undefined) {
      sanitized[key] = null;
    } else if (typeof value === 'object' && !Array.isArray(value)) {
      sanitized[key] = sanitizeMetadata(value);
    } else {
      // Skip arrays and other types
      sanitized[key] = null;
    }
  }

  return sanitized;
}

/**
 * Validate and sanitize IP address
 *
 * @param ip - IP address string
 * @returns Sanitized IP or null if invalid
 */
export function sanitizeIPAddress(ip: string | null): string | null {
  if (!ip) return null;

  // Validate it's actually an IP
  if (validator.isIP(ip, 4) || validator.isIP(ip, 6)) {
    return ip;
  }

  return null;
}
