/**
 * Content Sanitization Utility
 * Uses DOMPurify for XSS protection and content cleaning
 */

import DOMPurify from 'dompurify';

// Default message formatter for when intl is not available
const defaultMessageFormatter = (messageKey, values = {}) => {
  // Fallback messages for when intl is not available
  const fallbackMessages = {
    'sanitizer.invalidInput': 'Invalid input: HTML content must be a string',
    'sanitizer.invalidInputNonEmpty': 'Invalid input: HTML content must be a non-empty string',
    'sanitizer.sanitizationFailed': `Sanitization failed: ${values.error || 'Unknown error'}`,
    'sanitizer.dangerousProtocolDetected': 'Dangerous protocol detected',
    'sanitizer.emailMultimediaNotSupported': 'Video/audio/canvas elements may not be supported in email clients',
    'sanitizer.emailPositioningNotSupported': 'Fixed/sticky positioning may not work in email clients',
    'sanitizer.emailModernCssLimited': 'CSS Grid and Flexbox have limited support in email clients',
    'sanitizer.emailViewportUnitsNotSupported': 'Viewport units and rem may not be supported in all email clients',
    'sanitizer.mobileTablesNotFriendly': 'Tables may not be mobile-friendly - consider using flexbox or grid',
    'sanitizer.mobileRelativeFontSizes': 'Consider using relative font sizes (em, rem, %) for better mobile scaling',
    'sanitizer.mobileFixedWidthsProblematic': 'Large fixed widths may not work well on mobile devices',
    'sanitizer.mobileRelativeUnits': 'Consider using relative units (rem, em, %) for better mobile responsiveness',
    'sanitizer.productionValidHtml': 'Provide valid HTML content before deploying to production',
    'sanitizer.productionSanitized': 'Content has been sanitized for security - review changes before deploying',
    'sanitizer.productionInlineCss': 'Consider inlining CSS for better email client compatibility',
    'sanitizer.productionLargeContent': `Content is large (${values.size || 'unknown'} characters) - consider optimizing for mobile performance`,
  };

  return fallbackMessages[messageKey] || messageKey;
};

// Constants for better maintainability
const SANITIZER_VARIANTS = {
  EMAIL: 'email',
  INAPP: 'inapp',
};

const SECURITY_LEVELS = {
  STANDARD: 'standard',
  STRICT: 'strict',
};

const CONTENT_LIMITS = {
  LARGE_CONTENT_SIZE: 50000,
  MIN_CONTENT_LENGTH: 0,
};

const DANGEROUS_PROTOCOLS = ['javascript:', 'data:', 'vbscript:'];

const EVENT_HANDLERS = [
  'onclick', 'onload', 'onerror', 'onmouseover', 'onmouseout',
  'onmousedown', 'onmouseup', 'onkeydown', 'onkeyup', 'onkeypress',
  'onfocus', 'onblur', 'onchange', 'onsubmit', 'onreset',
];

// Email-specific sanitization config
const EMAIL_CONFIG = {
  ALLOWED_TAGS: [
    'html', 'head', 'title', 'meta', 'style', 'body',
    'div', 'span', 'p', 'br', 'hr', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
    'a', 'img', 'table', 'tr', 'td', 'th', 'thead', 'tbody', 'tfoot',
    'ul', 'ol', 'li', 'strong', 'b', 'em', 'i', 'u', 'center',
    'font', 'small', 'big', 'sup', 'sub', 'pre', 'code',
    'blockquote', 'cite', 'abbr', 'acronym', 'address',
  ],
  ALLOWED_ATTR: [
    'src', 'alt', 'title', 'href', 'target', 'rel',
    'width', 'height', 'style', 'class', 'id',
    'align', 'valign', 'bgcolor', 'color', 'border',
    'cellpadding', 'cellspacing', 'colspan', 'rowspan',
    'type', 'charset', 'content', 'name', 'http-equiv',
  ],
  FORBID_TAGS: ['script', 'iframe', 'object', 'embed', 'applet', 'form', 'input'],
  FORBID_ATTR: ['onclick', 'onload', 'onerror', 'onmouseover'],
  ALLOW_DATA_ATTR: false,
};

// InApp-specific sanitization config
const INAPP_CONFIG = {
  ALLOWED_TAGS: [
    'html', 'head', 'title', 'meta', 'style', 'body',
    'div', 'span', 'p', 'br', 'hr', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
    'a', 'img', 'button', 'ul', 'ol', 'li', 'strong', 'b', 'em', 'i', 'u',
    'small', 'big', 'sup', 'sub', 'pre', 'code', 'blockquote', 'cite',
    'video', 'audio', 'source', 'canvas', // Mobile-friendly multimedia
  ],
  ALLOWED_ATTR: [
    'src', 'alt', 'title', 'href', 'target', 'rel',
    'width', 'height', 'style', 'class', 'id',
    'type', 'controls', 'autoplay', 'loop', 'muted',
    'poster', 'preload',
  ],
  FORBID_TAGS: ['script', 'iframe', 'object', 'embed', 'applet', 'form', 'input'],
  FORBID_ATTR: ['onclick', 'onload', 'onerror', 'onmouseover'],
  ALLOW_DATA_ATTR: true,
};

// Strict sanitization config for production
const STRICT_CONFIG = {
  ALLOWED_TAGS: [
    'div', 'span', 'p', 'br', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
    'a', 'img', 'strong', 'b', 'em', 'i', 'u', 'ul', 'ol', 'li',
  ],
  ALLOWED_ATTR: ['src', 'alt', 'title', 'href', 'style', 'class'],
  FORBID_TAGS: ['script', 'iframe', 'object', 'embed', 'applet', 'form', 'input', 'style'],
  FORBID_ATTR: ['onclick', 'onload', 'onerror', 'onmouseover'],
  ALLOW_DATA_ATTR: false,
};

/**
 * Sanitizes HTML content based on variant and security level
 * @param {string} html - HTML content to sanitize
 * @param {string} variant - Editor variant (SANITIZER_VARIANTS.EMAIL or SANITIZER_VARIANTS.INAPP)
 * @param {string} level - Security level (SECURITY_LEVELS.STANDARD or SECURITY_LEVELS.STRICT)
 * @param {Function} formatMessage - Message formatter function for internationalization
 * @returns {Object} Sanitization result with sanitized content, cleanliness status, removed elements, and warnings
 */
export const sanitizeHTML = (html, variant = SANITIZER_VARIANTS.EMAIL, level = SECURITY_LEVELS.STANDARD, formatMessage = defaultMessageFormatter) => {
  // Input validation with better error handling
  if (html === null || html === undefined || typeof html !== 'string') {
    return {
      sanitized: '',
      isClean: true,
      removedElements: [],
      warnings: html === null || html === undefined ? [] : [{
        type: 'warning',
        message: formatMessage('sanitizer.invalidInput'),
        source: 'sanitizer',
        rule: 'sanitizer.invalidInput', // Rule Group #1 – blocking error for UI gating
      }],
    };
  }

  // Handle empty string as valid input (no warnings needed)
  if (html === '') {
    return {
      sanitized: '',
      isClean: true,
      removedElements: [],
      warnings: [],
    };
  }

  // Validate variant parameter
  const validVariants = Object.values(SANITIZER_VARIANTS);
  if (!validVariants.includes(variant)) {
    console.warn(`contentSanitizer: Invalid variant "${variant}". Valid variants are: ${validVariants.join(', ')}`);
    variant = SANITIZER_VARIANTS.EMAIL; // Fallback to email
  }

  // Validate level parameter
  const validLevels = Object.values(SECURITY_LEVELS);
  if (!validLevels.includes(level)) {
    console.warn(`contentSanitizer: Invalid security level "${level}". Valid levels are: ${validLevels.join(', ')}`);
    level = SECURITY_LEVELS.STANDARD; // Fallback to standard
  }

  const result = {
    sanitized: '',
    isClean: true,
    removedElements: [],
    warnings: [],
  };

  try {
    // Select configuration based on variant and level using constants
    let config;
    if (level === SECURITY_LEVELS.STRICT) {
      config = STRICT_CONFIG;
    } else {
      config = variant === SANITIZER_VARIANTS.INAPP ? INAPP_CONFIG : EMAIL_CONFIG;
    }

    // Configure DOMPurify
    const purifyConfig = {
      ALLOWED_TAGS: config.ALLOWED_TAGS,
      ALLOWED_ATTR: config.ALLOWED_ATTR,
      FORBID_TAGS: config.FORBID_TAGS,
      FORBID_ATTR: config.FORBID_ATTR,
      ALLOW_DATA_ATTR: config.ALLOW_DATA_ATTR,
      RETURN_DOM: false,
      RETURN_DOM_FRAGMENT: false,
      RETURN_DOM_IMPORT: false,
      SANITIZE_DOM: true,
      KEEP_CONTENT: true,
      ADD_TAGS: [],
      ADD_ATTR: [],
      CUSTOM_ELEMENT_HANDLING: {
        tagNameCheck: null,
        attributeNameCheck: null,
        allowCustomizedBuiltInElements: false,
      },
    };

    // Sanitize the content directly
    result.sanitized = DOMPurify.sanitize(html, purifyConfig);

    // Additional checks and warnings
    if (result.sanitized !== html) {
      result.isClean = false;
    }

    // Add variant-specific warnings (check original HTML before sanitization)
    addVariantWarnings(html, variant, result, formatMessage);
  } catch (error) {
    result.warnings.push({
      type: 'error',
      message: formatMessage('sanitizer.sanitizationFailed', { error: error.message }),
      source: 'sanitizer',
      rule: 'sanitizer.sanitizationFailed', // Rule Group #1 – blocking error for UI gating
    });
    result.sanitized = ''; // Return empty content if sanitization fails
    result.isClean = false;
  }

  return result;
};

/**
 * Adds variant-specific warnings based on content analysis
 * @param {string} html - HTML content to analyze
 * @param {string} variant - Editor variant
 * @param {Object} result - Result object to add warnings to
 * @param {Function} formatMessage - Message formatter function
 */
const addVariantWarnings = (html, variant, result, formatMessage = defaultMessageFormatter) => {
  if (!html || typeof html !== 'string') return;

  if (variant === SANITIZER_VARIANTS.EMAIL) {
    // Check for potentially problematic email elements
    const emailProblematicElements = ['<video', '<audio', '<canvas'];
    if (emailProblematicElements.some((element) => html.includes(element))) {
      result.warnings.push({
        type: 'warning',
        message: formatMessage('sanitizer.emailMultimediaNotSupported'),
        source: 'email-compatibility',
      });
    }

    const problematicStyles = ['position: fixed', 'position: sticky', 'position:fixed', 'position:sticky'];
    if (problematicStyles.some((style) => html.includes(style))) {
      result.warnings.push({
        type: 'warning',
        message: formatMessage('sanitizer.emailPositioningNotSupported'),
        source: 'email-compatibility',
      });
    }

    // Check for CSS Grid/Flexbox which may have limited email support
    const modernCssFeatures = ['display: grid', 'display: flex', 'display:grid', 'display:flex'];
    if (modernCssFeatures.some((feature) => html.includes(feature))) {
      result.warnings.push({
        type: 'info',
        message: formatMessage('sanitizer.emailModernCssLimited'),
        source: 'email-compatibility',
      });
    }
  } else if (variant === SANITIZER_VARIANTS.INAPP) {
    // Check for potentially problematic mobile elements
    if (html.includes('<table')) {
      result.warnings.push({
        type: 'info',
        message: formatMessage('sanitizer.mobileTablesNotFriendly'),
        source: 'mobile-optimization',
      });
    }

    // Check for fixed pixel font sizes
    if (html.includes('font-size') && /font-size:\s*[0-9]+px/g.test(html)) {
      result.warnings.push({
        type: 'info',
        message: formatMessage('sanitizer.mobileRelativeFontSizes'),
        source: 'mobile-optimization',
      });
    }

    // Check for fixed pixel widths that might not be mobile-friendly
    if (/width:\s*[0-9]{3,}px/g.test(html)) {
      result.warnings.push({
        type: 'info',
        message: formatMessage('sanitizer.mobileFixedWidthsProblematic'),
        source: 'mobile-optimization',
      });
    }
  }
};

/**
 * Validates and sanitizes content for production use
 * @param {string} html - HTML content
 * @param {string} variant - Editor variant (SANITIZER_VARIANTS.EMAIL or SANITIZER_VARIANTS.INAPP)
 * @param {Function} formatMessage - Message formatter function for internationalization
 * @returns {Object} Production-ready content with validation results and recommendations
 */
export const prepareForProduction = (html, variant = SANITIZER_VARIANTS.EMAIL, formatMessage = defaultMessageFormatter) => {
  // Input validation
  if (!html || typeof html !== 'string') {
    return {
      content: '',
      isProductionReady: false,
      securityIssues: [],
      warnings: [{
        type: 'error',
        message: formatMessage('sanitizer.invalidInputNonEmpty'),
        source: 'production-validator',
      }],
      recommendations: [formatMessage('sanitizer.productionValidHtml')],
    };
  }

  // First, sanitize with strict rules
  const sanitizeResult = sanitizeHTML(html, variant, SECURITY_LEVELS.STRICT, formatMessage);

  const result = {
    content: sanitizeResult.sanitized,
    isProductionReady: sanitizeResult.isClean,
    securityIssues: sanitizeResult.removedElements,
    warnings: sanitizeResult.warnings,
    recommendations: [],
  };

  // Add production readiness recommendations
  if (!result.isProductionReady) {
    result.recommendations.push(formatMessage('sanitizer.productionSanitized'));
  }

  if (variant === SANITIZER_VARIANTS.EMAIL && html.includes('<style>')) {
    result.recommendations.push(formatMessage('sanitizer.productionInlineCss'));
  }

  if (variant === SANITIZER_VARIANTS.INAPP && html.length > CONTENT_LIMITS.LARGE_CONTENT_SIZE) {
    result.recommendations.push(formatMessage('sanitizer.productionLargeContent', { size: html.length }));
  }

  // Additional variant-specific recommendations
  if (variant === SANITIZER_VARIANTS.EMAIL) {
    if (html.includes('rem') || html.includes('vh') || html.includes('vw')) {
      result.recommendations.push(formatMessage('sanitizer.emailViewportUnitsNotSupported'));
    }
  } else if (variant === SANITIZER_VARIANTS.INAPP) {
    if (html.includes('px') && html.length > CONTENT_LIMITS.LARGE_CONTENT_SIZE / 2) {
      result.recommendations.push(formatMessage('sanitizer.mobileRelativeUnits'));
    }
  }

  return result;
};

/**
 * Quick security check for content
 * @param {string} html - HTML content to check
 * @returns {boolean} True if content appears safe
 */
export const isContentSafe = (html) => {
  if (!html || typeof html !== 'string') return true;

  // Create dynamic patterns from constants
  const protocolPatterns = DANGEROUS_PROTOCOLS.map((protocol) => new RegExp(protocol.replace(':', '\\:'), 'gi'));

  const eventHandlerPattern = new RegExp(EVENT_HANDLERS.join('|'), 'gi');

  const dangerousPatterns = [
    ...protocolPatterns,
    /<script/gi,
    eventHandlerPattern,
    /<iframe/gi,
    /<object/gi,
    /<embed/gi,
    /<applet/gi,
    /<form/gi,
  ];

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

/**
 * Extracts potentially unsafe content for review
 * @param {string} html - HTML content to analyze
 * @returns {Array} List of unsafe patterns found with details
 */
export const findUnsafeContent = (html) => {
  if (!html || typeof html !== 'string') return [];

  const unsafeContent = [];

  // Build patterns dynamically from constants
  const patterns = {
    'JavaScript Protocol': new RegExp(DANGEROUS_PROTOCOLS[0].replace(':', '\\:'), 'gi'),
    'Data URL': new RegExp(DANGEROUS_PROTOCOLS[1].replace(':', '\\:'), 'gi'),
    'VBScript Protocol': new RegExp(DANGEROUS_PROTOCOLS[2].replace(':', '\\:'), 'gi'),
    'Script Tag': /<script[^>]*>/gi,
    'Event Handler': new RegExp(`(${EVENT_HANDLERS.join('|')})\\s*=`, 'gi'),
    'Iframe': /<iframe[^>]*>/gi,
    'Object/Embed': /<(object|embed)[^>]*>/gi,
    'Applet': /<applet[^>]*>/gi,
    'Form': /<form[^>]*>/gi,
  };

  Object.entries(patterns).forEach(([name, pattern]) => {
    let match;
    // Use exec in a loop to find all matches with positions
    while ((match = pattern.exec(html)) !== null) {
      unsafeContent.push({
        type: name,
        content: match[0],
        position: match.index,
        length: match[0].length,
      });

      // Prevent infinite loop for global patterns
      if (!pattern.global) break;
    }
  });

  // Sort by position for easier review
  return unsafeContent.sort((a, b) => a.position - b.position);
};

// Export constants for external use
export { SANITIZER_VARIANTS, SECURITY_LEVELS, CONTENT_LIMITS };

export default {
  sanitizeHTML,
  prepareForProduction,
  isContentSafe,
  findUnsafeContent,
  // Include constants in default export for convenience
  VARIANTS: SANITIZER_VARIANTS,
  SECURITY_LEVELS,
  CONTENT_LIMITS,
};
