import React from 'react';
import Image from 'next/image';
import Link from 'next/link';
import { cn } from '../../lib/utils';
import { processHTML } from '../../lib/html-compat';
import { getMediaByUrl, getMediaById, getAssetMap } from '../../lib/data';

interface ContentRendererProps {
  content: string;
  className?: string;
  sanitize?: boolean;
  processAssets?: boolean;
  convertClasses?: boolean;
}

interface ProcessedImage {
  src: string;
  alt: string;
  width?: number;
  height?: number;
}

/**
 * ContentRenderer Component
 * Handles rendering of WordPress HTML content with proper sanitization
 * and conversion to modern React components
 */
export const ContentRenderer: React.FC<ContentRendererProps> = ({
  content,
  className = '',
  sanitize = true,
  processAssets = true,
  convertClasses = true,
}) => {
  // Process the HTML content
  const processedContent = React.useMemo(() => {
    let html = content;
    
    if (sanitize) {
      html = processHTML(html);
    }
    
    if (processAssets) {
      html = replaceWordPressAssets(html);
    }
    
    if (convertClasses) {
      html = convertWordPressClasses(html);
    }
    
    return html;
  }, [content, sanitize, processAssets, convertClasses]);

  // Parse and render the HTML
  const renderContent = () => {
    if (!processedContent) return null;

    // Use a parser to convert HTML to React elements
    // For security, we'll use a custom parser that only allows safe elements
    return parseHTMLToReact(processedContent);
  };

  return (
    <div className={cn(
      'prose prose-lg max-w-none',
      'prose-headings:font-bold prose-headings:tracking-tight',
      'prose-h1:text-3xl prose-h1:md:text-4xl prose-h1:mb-4',
      'prose-h2:text-2xl prose-h2:md:text-3xl prose-h2:mb-3',
      'prose-h3:text-xl prose-h3:md:text-2xl prose-h3:mb-2',
      'prose-p:text-gray-700 prose-p:leading-relaxed prose-p:mb-4',
      'prose-a:text-primary prose-a:hover:text-primary-dark prose-a:underline',
      'prose-ul:list-disc prose-ul:pl-6 prose-ul:mb-4',
      'prose-ol:list-decimal prose-ol:pl-6 prose-ol:mb-4',
      'prose-li:mb-2 prose-li:marker:text-primary',
      'prose-strong:font-bold prose-strong:text-gray-900',
      'prose-em:italic prose-em:text-gray-700',
      'prose-table:w-full prose-table:border-collapse prose-table:my-4',
      'prose-th:bg-gray-100 prose-th:font-bold prose-th:p-2 prose-th:text-left',
      'prose-td:p-2 prose-td:border prose-td:border-gray-200',
      'prose-img:rounded-lg prose-img:shadow-md prose-img:my-4',
      'prose-blockquote:border-l-4 prose-blockquote:border-primary prose-blockquote:pl-4 prose-blockquote:italic prose-blockquote:bg-gray-50 prose-blockquote:py-2 prose-blockquote:my-4',
      className
    )}>
      {renderContent()}
    </div>
  );
};

/**
 * Parse HTML string to React elements
 * This is a safe parser that only allows specific tags and attributes
 * Works in both server and client environments
 */
function parseHTMLToReact(html: string): React.ReactNode {
  // For server-side rendering, use a simple approach with dangerouslySetInnerHTML
  // The HTML has already been sanitized by processHTML, so it's safe
  if (typeof window === 'undefined') {
    return <div dangerouslySetInnerHTML={{ __html: html }} />;
  }

  // Client-side: use DOMParser for proper parsing
  // Define allowed tags and their properties
  const allowedTags = {
    div: ['className', 'id', 'style'],
    p: ['className', 'style'],
    h1: ['className', 'style'],
    h2: ['className', 'style'],
    h3: ['className', 'style'],
    h4: ['className', 'style'],
    h5: ['className', 'style'],
    h6: ['className', 'style'],
    span: ['className', 'style'],
    a: ['href', 'target', 'rel', 'className', 'title', 'style'],
    ul: ['className', 'style'],
    ol: ['className', 'style'],
    li: ['className', 'style'],
    strong: ['className', 'style'],
    b: ['className', 'style'],
    em: ['className', 'style'],
    i: ['className', 'style'],
    br: [],
    hr: ['className', 'style'],
    img: ['src', 'alt', 'width', 'height', 'className', 'style'],
    table: ['className', 'style'],
    thead: ['className', 'style'],
    tbody: ['className', 'style'],
    tr: ['className', 'style'],
    th: ['className', 'style'],
    td: ['className', 'style'],
    blockquote: ['className', 'style'],
    code: ['className', 'style'],
    pre: ['className', 'style'],
    small: ['className', 'style'],
    section: ['className', 'id', 'style'],
    article: ['className', 'id', 'style'],
    figure: ['className', 'style'],
    figcaption: ['className', 'style'],
    video: ['className', 'style', 'autoPlay', 'loop', 'muted', 'playsInline', 'poster'],
    source: ['src', 'type'],
  };

  // Create a temporary DOM element to parse the HTML
  const parser = new DOMParser();
  const doc = parser.parseFromString(html, 'text/html');
  const body = doc.body;

  // Recursive function to convert DOM nodes to React elements
  function convertNode(node: Node, index: number): React.ReactNode {
    if (node.nodeType === Node.TEXT_NODE) {
      return node.textContent;
    }

    if (node.nodeType !== Node.ELEMENT_NODE) {
      return null;
    }

    const element = node as HTMLElement;
    const tagName = element.tagName.toLowerCase();

    // Check if tag is allowed
    if (!allowedTags[tagName as keyof typeof allowedTags]) {
      // For unknown tags, just render their children
      return Array.from(node.childNodes).map((child, i) => convertNode(child, i));
    }

    // Build props
    const props: any = { key: index };
    const allowedProps = allowedTags[tagName as keyof typeof allowedTags];

    // Helper function to convert style string to object
    const parseStyleString = (styleStr: string): React.CSSProperties => {
      const styles: React.CSSProperties = {};
      if (!styleStr) return styles;
      
      styleStr.split(';').forEach(style => {
        const [key, value] = style.split(':').map(s => s.trim());
        if (key && value) {
          // Convert camelCase for React
          const camelKey = key.replace(/-([a-z])/g, (g) => g[1].toUpperCase());
          (styles as any)[camelKey] = value;
        }
      });
      
      return styles;
    };

    // Handle special cases for different element types
    if (tagName === 'a' && element.getAttribute('href')) {
      const href = element.getAttribute('href')!;
      const isExternal = href.startsWith('http') && !href.includes(window?.location?.hostname || '');
      
      if (isExternal) {
        props.href = href;
        props.target = '_blank';
        props.rel = 'noopener noreferrer';
      } else {
        // For internal links, use Next.js Link
        const children = Array.from(node.childNodes).map((child, i) => convertNode(child, i));
        return (
          <Link
            href={href}
            key={index}
            className={element.className}
            style={parseStyleString(element.style.cssText)}
          >
            {children}
          </Link>
        );
      }
    }

    if (tagName === 'img') {
      const src = element.getAttribute('src') || '';
      const alt = element.getAttribute('alt') || '';
      const widthAttr = element.getAttribute('width');
      const heightAttr = element.getAttribute('height');
      const dataWpImageId = element.getAttribute('data-wp-image-id');
      
      // Handle WordPress image IDs
      if (dataWpImageId) {
        const media = getMediaById(parseInt(dataWpImageId));
        if (media) {
          const width = widthAttr ? parseInt(widthAttr) : (media.width || 800);
          const height = heightAttr ? parseInt(heightAttr) : (media.height || 600);
          
          return (
            <Image
              key={index}
              src={media.localPath}
              alt={alt || media.alt || ''}
              width={width}
              height={height}
              className={element.className || ''}
              style={parseStyleString(element.style.cssText)}
              priority={false}
              sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
            />
          );
        }
      }
      
      // Handle regular image URLs
      if (src) {
        const imageProps = getImageProps(src);
        const width = widthAttr ? parseInt(widthAttr) : imageProps.width;
        const height = heightAttr ? parseInt(heightAttr) : imageProps.height;
        
        // Check if it's an external URL
        if (src.startsWith('http')) {
          // For external images, use regular img tag
          return (
            <img
              key={index}
              src={imageProps.src}
              alt={alt}
              width={width}
              height={height}
              className={element.className || ''}
              style={parseStyleString(element.style.cssText)}
            />
          );
        }
        
        return (
          <Image
            key={index}
            src={imageProps.src}
            alt={alt || imageProps.alt || ''}
            width={width || 800}
            height={height || 600}
            className={element.className || ''}
            style={parseStyleString(element.style.cssText)}
            priority={false}
            sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
          />
        );
      }
      return null;
    }

    // Handle video elements
    if (tagName === 'video') {
      const videoProps: any = { key: index };
      
      // Get sources
      const sources: React.ReactNode[] = [];
      Array.from(element.childNodes).forEach((child, i) => {
        if (child.nodeType === Node.ELEMENT_NODE && (child as HTMLElement).tagName.toLowerCase() === 'source') {
          const sourceEl = child as HTMLSourceElement;
          sources.push(
            <source key={i} src={sourceEl.src} type={sourceEl.type} />
          );
        }
      });
      
      // Set video props
      if (element.className) videoProps.className = element.className;
      if (element.style.cssText) videoProps.style = parseStyleString(element.style.cssText);
      if (element.getAttribute('autoPlay')) videoProps.autoPlay = true;
      if (element.getAttribute('loop')) videoProps.loop = true;
      if (element.getAttribute('muted')) videoProps.muted = true;
      if (element.getAttribute('playsInline')) videoProps.playsInline = true;
      if (element.getAttribute('poster')) videoProps.poster = element.getAttribute('poster');
      
      return (
        <video {...videoProps}>
          {sources}
        </video>
      );
    }

    // Handle divs with special data attributes for backgrounds
    if (tagName === 'div' && element.getAttribute('data-color-overlay')) {
      const colorOverlay = element.getAttribute('data-color-overlay');
      const overlayOpacity = parseFloat(element.getAttribute('data-overlay-opacity') || '0.5');
      
      // Get the original classes and style
      const className = element.className;
      const style = parseStyleString(element.style.cssText);
      
      // Convert children
      const children = Array.from(node.childNodes).map((child, i) => convertNode(child, i));
      
      return (
        <div key={index} className={className} style={style}>
          <div
            className="absolute inset-0"
            style={{ backgroundColor: colorOverlay, opacity: overlayOpacity }}
          />
          <div className="relative">
            {children}
          </div>
        </div>
      );
    }

    // Handle divs with video background data attributes
    if (tagName === 'div' && element.getAttribute('data-video-bg') === 'true') {
      const className = element.className;
      const style = parseStyleString(element.style.cssText);
      const mp4 = element.getAttribute('data-video-mp4');
      const webm = element.getAttribute('data-video-webm');
      
      const children = Array.from(node.childNodes).map((child, i) => convertNode(child, i));
      
      return (
        <div key={index} className={className} style={style}>
          {mp4 || webm ? (
            <video
              className="absolute inset-0 w-full h-full object-cover"
              autoPlay
              loop
              muted
              playsInline
            >
              {mp4 && <source src={mp4} type="video/mp4" />}
              {webm && <source src={webm} type="video/webm" />}
            </video>
          ) : null}
          <div className="relative z-10">
            {children}
          </div>
        </div>
      );
    }

    // Standard attribute mapping
    allowedProps.forEach(prop => {
      if (prop === 'style') {
        // Handle style separately
        if (element.style.cssText) {
          props.style = parseStyleString(element.style.cssText);
        }
      } else {
        const value = element.getAttribute(prop);
        if (value !== null) {
          props[prop] = value;
        }
      }
    });

    // Handle className specifically
    if (element.className && allowedProps.includes('className')) {
      props.className = element.className;
    }

    // Convert children
    const children = Array.from(node.childNodes).map((child, i) => convertNode(child, i));

    // Return React element
    return React.createElement(tagName, props, children);
  }

  // Convert all children of body
  return Array.from(body.childNodes).map((node, index) => convertNode(node, index));
}

/**
 * Replace WordPress asset URLs with local paths
 */
function replaceWordPressAssets(html: string): string {
  try {
    // Use the data layer to replace URLs
    const assetMap = getAssetMap();
    let processed = html;
    
    // Replace URLs in src attributes
    Object.entries(assetMap).forEach(([wpUrl, localPath]) => {
      // Handle both full URLs and relative paths
      const urlPattern = new RegExp(wpUrl.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g');
      processed = processed.replace(urlPattern, localPath as string);
    });
    
    // Also handle any remaining WordPress URLs that might be in the format we expect
    processed = processed.replace(/https?:\/\/[^"'\s]+\/wp-content\/uploads\/\d{4}\/\d{2}\/([^"'\s]+)/g, (match, filename) => {
      // Try to find this file in our media
      const media = getMediaByUrl(match);
      if (media) {
        return media.localPath;
      }
      return match;
    });
    
    return processed;
  } catch (error) {
    console.warn('Error replacing asset URLs:', error);
    return html;
  }
}

/**
 * Convert WordPress/Salient classes to Tailwind equivalents
 */
function convertWordPressClasses(html: string): string {
  const classMap: Record<string, string> = {
    // Salient/Vc_row classes
    'vc_row': 'flex flex-wrap -mx-4',
    'vc_row-fluid': 'w-full',
    'vc_col-sm-12': 'w-full px-4',
    'vc_col-md-6': 'w-full md:w-1/2 px-4',
    'vc_col-md-4': 'w-full md:w-1/3 px-4',
    'vc_col-md-3': 'w-full md:w-1/4 px-4',
    'vc_col-lg-6': 'w-full lg:w-1/2 px-4',
    'vc_col-lg-4': 'w-full lg:w-1/3 px-4',
    'vc_col-lg-3': 'w-full lg:w-1/4 px-4',
    
    // Typography
    'wpb_wrapper': 'space-y-4',
    'wpb_text_column': 'prose max-w-none',
    'wpb_content_element': 'mb-8',
    'wpb_single_image': 'my-4',
    'wpb_heading': 'text-2xl font-bold mb-2',
    
    // Alignment
    'text-left': 'text-left',
    'text-center': 'text-center',
    'text-right': 'text-right',
    'alignleft': 'float-left mr-4 mb-4',
    'alignright': 'float-right ml-4 mb-4',
    'aligncenter': 'mx-auto',
    
    // Colors
    'accent-color': 'text-primary',
    'primary-color': 'text-primary',
    'secondary-color': 'text-secondary',
    'text-color': 'text-gray-800',
    'light-text': 'text-gray-300',
    'dark-text': 'text-gray-900',
    
    // Backgrounds
    'bg-light': 'bg-gray-50',
    'bg-light-gray': 'bg-gray-100',
    'bg-dark': 'bg-gray-900',
    'bg-dark-gray': 'bg-gray-800',
    'bg-primary': 'bg-primary',
    'bg-secondary': 'bg-secondary',
    'bg-white': 'bg-white',
    'bg-transparent': 'bg-transparent',
    
    // Buttons
    'btn': 'inline-flex items-center justify-center px-4 py-2 rounded-lg font-semibold transition-colors duration-200',
    'btn-primary': 'bg-primary text-white hover:bg-primary-dark',
    'btn-secondary': 'bg-secondary text-white hover:bg-secondary-light',
    'btn-outline': 'border-2 border-primary text-primary hover:bg-primary hover:text-white',
    'btn-large': 'px-6 py-3 text-lg',
    'btn-small': 'px-3 py-1 text-sm',
    
    // Containers
    'container': 'container mx-auto px-4',
    'container-fluid': 'w-full px-4',
    
    // Spacing
    'mt-0': 'mt-0', 'mb-0': 'mb-0',
    'mt-2': 'mt-2', 'mb-2': 'mb-2',
    'mt-4': 'mt-4', 'mb-4': 'mb-4',
    'mt-6': 'mt-6', 'mb-6': 'mb-6',
    'mt-8': 'mt-8', 'mb-8': 'mb-8',
    'mt-12': 'mt-12', 'mb-12': 'mb-12',
    
    // WordPress specific
    'wp-caption': 'figure',
    'wp-caption-text': 'figcaption text-sm text-gray-600 mt-2',
    'alignnone': 'block',
    'size-full': 'w-full',
    'size-large': 'w-full max-w-3xl',
    'size-medium': 'w-full max-w-xl',
    'size-thumbnail': 'w-32 h-32',
  };

  let processed = html;
  
  // Replace classes in HTML
  Object.entries(classMap).forEach(([wpClass, twClass]) => {
    // Handle class="..." with the class at the beginning
    const classRegex1 = new RegExp(`class=["']${wpClass}\\s+([^"']*)["']`, 'g');
    processed = processed.replace(classRegex1, (match, rest) => {
      const newClasses = `${twClass} ${rest}`.trim().replace(/\s+/g, ' ');
      return `class="${newClasses}"`;
    });
    
    // Handle class="..." with the class in the middle
    const classRegex2 = new RegExp(`class=["']([^"']*)\\s+${wpClass}\\s+([^"']*)["']`, 'g');
    processed = processed.replace(classRegex2, (match, before, after) => {
      const newClasses = `${before} ${twClass} ${after}`.trim().replace(/\s+/g, ' ');
      return `class="${newClasses}"`;
    });
    
    // Handle class="..." with the class at the end
    const classRegex3 = new RegExp(`class=["']([^"']*)\\s+${wpClass}["']`, 'g');
    processed = processed.replace(classRegex3, (match, before) => {
      const newClasses = `${before} ${twClass}`.trim().replace(/\s+/g, ' ');
      return `class="${newClasses}"`;
    });
    
    // Handle class="..." with only the class
    const classRegex4 = new RegExp(`class=["']${wpClass}["']`, 'g');
    processed = processed.replace(classRegex4, `class="${twClass}"`);
  });

  return processed;
}

/**
 * Get image props from source using the data layer
 */
function getImageProps(src: string): { src: string; width?: number; height?: number; alt?: string } {
  // Check if it's a data attribute for WordPress image ID
  if (src.startsWith('data-wp-image-id:')) {
    const imageId = src.replace('data-wp-image-id:', '');
    const media = getMediaById(parseInt(imageId));
    if (media) {
      return {
        src: media.localPath,
        width: media.width || 800,
        height: media.height || 600,
        alt: media.alt || ''
      };
    }
  }
  
  // Try to find by URL
  const media = getMediaByUrl(src);
  if (media) {
    return {
      src: media.localPath,
      width: media.width || 800,
      height: media.height || 600,
      alt: media.alt || ''
    };
  }
  
  // Check if it's already a local path
  if (src.startsWith('/media/')) {
    return { src, width: 800, height: 600 };
  }
  
  // Return as-is for external URLs
  return { src, width: 800, height: 600 };
}

/**
 * Process background attributes and convert to inline styles
 */
function processBackgroundAttributes(element: HTMLElement): { style?: string; className?: string } {
  const result: { style?: string; className?: string } = {};
  const styles: string[] = [];
  const classes: string[] = [];
  
  // Check for data attributes from shortcodes
  const bgImage = element.getAttribute('data-bg-image');
  const bgVideo = element.getAttribute('data-video-bg');
  const videoMp4 = element.getAttribute('data-video-mp4');
  const videoWebm = element.getAttribute('data-video-webm');
  const parallax = element.getAttribute('data-parallax');
  
  // Handle background image
  if (bgImage) {
    const media = getMediaById(parseInt(bgImage));
    if (media) {
      styles.push(`background-image: url(${media.localPath})`);
      styles.push('background-size: cover');
      styles.push('background-position: center');
      classes.push('bg-cover', 'bg-center');
    }
  }
  
  // Handle video background
  if (bgVideo === 'true' && (videoMp4 || videoWebm)) {
    // This will be handled by a separate video component
    // For now, we'll add a marker class
    classes.push('has-video-background');
    if (videoMp4) element.setAttribute('data-video-mp4', videoMp4);
    if (videoWebm) element.setAttribute('data-video-webm', videoWebm);
  }
  
  // Handle parallax
  if (parallax === 'true') {
    classes.push('parallax-bg');
  }
  
  // Handle inline styles from shortcode attributes
  const colorOverlay = element.getAttribute('color_overlay');
  const overlayStrength = element.getAttribute('overlay_strength');
  const topPadding = element.getAttribute('top_padding');
  const bottomPadding = element.getAttribute('bottom_padding');
  
  if (colorOverlay) {
    const opacity = overlayStrength ? parseFloat(overlayStrength) : 0.5;
    styles.push(`position: relative`);
    classes.push('relative');
    
    // Add overlay as a child element marker
    element.setAttribute('data-color-overlay', colorOverlay);
    element.setAttribute('data-overlay-opacity', opacity.toString());
  }
  
  if (topPadding) {
    styles.push(`padding-top: ${topPadding}`);
  }
  
  if (bottomPadding) {
    styles.push(`padding-bottom: ${bottomPadding}`);
  }
  
  if (styles.length > 0) {
    result.style = styles.join('; ');
  }
  
  if (classes.length > 0) {
    result.className = classes.join(' ');
  }
  
  return result;
}

// Sub-components for specific content types
export const ContentBlock: React.FC<{
  title?: string;
  content: string;
  className?: string;
}> = ({ title, content, className = '' }) => (
  <div className={cn('mb-8', className)}>
    {title && <h3 className="text-2xl font-bold mb-4">{title}</h3>}
    <ContentRenderer content={content} />
  </div>
);

export const RichText: React.FC<{
  html: string;
  className?: string;
}> = ({ html, className = '' }) => (
  <ContentRenderer content={html} className={className} />
);

export default ContentRenderer;