"""
Content Normalizer - Normalizes AI-generated content from different formats
Handles full HTML documents, HTML fragments, and plain text
Preserves HTML structure for future use on blogs/pages
"""
import re
import logging
from typing import Dict, Any, Optional

logger = logging.getLogger(__name__)

# Try to import BeautifulSoup, fallback to regex if not available
try:
    from bs4 import BeautifulSoup
    HAS_BEAUTIFULSOUP = True
except ImportError:
    HAS_BEAUTIFULSOUP = False
    logger.warning("BeautifulSoup4 not available, using regex fallback for HTML parsing")


def normalize_content(content: str, content_format: Optional[str] = None) -> Dict[str, Any]:
    """
    Normalize content from different AI response formats.
    
    Args:
        content: Raw content from AI (can be full HTML, HTML fragments, or plain text)
        content_format: Optional hint about format ('html_document', 'html_fragment', 'plain_text')
    
    Returns:
        Dict with:
            - 'normalized_content': Clean HTML ready for display and storage
            - 'content_type': 'html' or 'text'
            - 'has_structure': bool (True if has headings, lists, etc.)
            - 'original_format': Detected format
    """
    if not content or not isinstance(content, str):
        return {
            'normalized_content': '',
            'content_type': 'text',
            'has_structure': False,
            'original_format': 'empty'
        }
    
    content = content.strip()
    
    # Detect format
    detected_format = content_format or _detect_content_format(content)
    
    logger.info(f"Normalizing content: format={detected_format}, length={len(content)}")
    
    try:
        if detected_format == 'html_document':
            # Extract body content from full HTML document
            normalized = _extract_body_content(content)
        elif detected_format == 'html_fragment':
            # Clean and normalize HTML fragments
            normalized = _normalize_html_fragment(content)
        else:
            # Plain text - convert to HTML
            normalized = _convert_text_to_html(content)
        
        # Final cleanup and validation
        normalized = _final_cleanup(normalized)
        
        # Check if content has structure (headings, lists, etc.)
        has_structure = _has_structure(normalized)
        
        return {
            'normalized_content': normalized,
            'content_type': 'html',
            'has_structure': has_structure,
            'original_format': detected_format
        }
        
    except Exception as e:
        logger.error(f"Error normalizing content: {e}", exc_info=True)
        # Fallback: return sanitized version
        return {
            'normalized_content': _escape_html(content),
            'content_type': 'text',
            'has_structure': False,
            'original_format': 'error'
        }


def _detect_content_format(content: str) -> str:
    """Detect the format of the content"""
    content_lower = content.lower().strip()
    
    # Check for full HTML document
    if (content_lower.startswith('<!doctype') or 
        content_lower.startswith('<html') or
        ('<html' in content_lower and '<body' in content_lower)):
        return 'html_document'
    
    # Check for HTML fragments (has HTML tags but not full document)
    if re.search(r'<[h1-6p]|</[h1-6p]|<ul|<ol|<li|<table|<div|<article|<section', content_lower):
        return 'html_fragment'
    
    # Plain text
    return 'plain_text'


def _extract_body_content(html_content: str) -> str:
    """Extract body content from full HTML document"""
    if HAS_BEAUTIFULSOUP:
        try:
            soup = BeautifulSoup(html_content, 'html.parser')
            
            # Find article, main, or body tag
            article = soup.find('article')
            if article:
                return str(article)
            
            main = soup.find('main')
            if main:
                return str(main)
            
            body = soup.find('body')
            if body:
                # Extract all children of body
                body_content = ''.join(str(child) for child in body.children)
                return body_content
            
            # If no body found, return the whole thing (shouldn't happen)
            return html_content
            
        except Exception as e:
            logger.warning(f"Error parsing HTML with BeautifulSoup: {e}")
    
    # Fallback: use regex to extract body content
    body_match = re.search(r'<body[^>]*>(.*?)</body>', html_content, re.DOTALL | re.IGNORECASE)
    if body_match:
        return body_match.group(1)
    
    # If still no body, try to extract article
    article_match = re.search(r'<article[^>]*>(.*?)</article>', html_content, re.DOTALL | re.IGNORECASE)
    if article_match:
        return article_match.group(1)
    
    # Try to extract main
    main_match = re.search(r'<main[^>]*>(.*?)</main>', html_content, re.DOTALL | re.IGNORECASE)
    if main_match:
        return main_match.group(1)
    
    return html_content


def _normalize_html_fragment(html_content: str) -> str:
    """Normalize HTML fragments - ensure proper structure"""
    if HAS_BEAUTIFULSOUP:
        try:
            soup = BeautifulSoup(html_content, 'html.parser')
            
            # Wrap in article if not already wrapped and has structure
            if not soup.find('article') and not soup.find('div', class_='content-wrapper'):
                # Check if content has structure
                if soup.find(['h1', 'h2', 'h3', 'h4', 'h5', 'h6']):
                    # Has headings - wrap in article
                    article = soup.new_tag('article')
                    # Move all top-level elements into article
                    for element in list(soup.children):
                        if hasattr(element, 'extract'):
                            article.append(element.extract())
                        else:
                            article.append(str(element))
                    soup.append(article)
            
            # Clean up empty tags (except br, hr, img)
            for tag in soup.find_all():
                if not tag.get_text(strip=True) and not tag.find_all(['img', 'br', 'hr']):
                    tag.decompose()
            
            return str(soup)
            
        except Exception as e:
            logger.warning(f"Error normalizing HTML fragment with BeautifulSoup: {e}")
    
    # Fallback: basic regex cleanup
    # Remove empty tags
    html_content = re.sub(r'<(\w+)[^>]*>\s*</\1>', '', html_content)
    # Wrap in article if not already wrapped
    if not re.search(r'<article', html_content, re.IGNORECASE):
        if re.search(r'<h[1-6]', html_content, re.IGNORECASE):
            html_content = f'<article>{html_content}</article>'
    
    return html_content


def _convert_text_to_html(text: str) -> str:
    """Convert plain text to HTML"""
    lines = text.split('\n')
    html_parts = []
    in_list = False
    
    for line in lines:
        trimmed = line.strip()
        
        if not trimmed:
            if in_list:
                html_parts.append('</ul>')
                in_list = False
            html_parts.append('<br>')
            continue
        
        # Check for headings (markdown style or plain)
        if trimmed.startswith('# '):
            if in_list:
                html_parts.append('</ul>')
                in_list = False
            html_parts.append(f'<h1>{_escape_html(trimmed[2:])}</h1>')
        elif trimmed.startswith('## '):
            if in_list:
                html_parts.append('</ul>')
                in_list = False
            html_parts.append(f'<h2>{_escape_html(trimmed[3:])}</h2>')
        elif trimmed.startswith('### '):
            if in_list:
                html_parts.append('</ul>')
                in_list = False
            html_parts.append(f'<h3>{_escape_html(trimmed[4:])}</h3>')
        elif trimmed.startswith('#### '):
            if in_list:
                html_parts.append('</ul>')
                in_list = False
            html_parts.append(f'<h4>{_escape_html(trimmed[5:])}</h4>')
        # Check for bullet points
        elif trimmed.startswith('- ') or trimmed.startswith('* '):
            if not in_list:
                html_parts.append('<ul>')
                in_list = True
            text = trimmed[2:].strip()
            html_parts.append(f'<li>{_escape_html(text)}</li>')
        else:
            if in_list:
                html_parts.append('</ul>')
                in_list = False
            html_parts.append(f'<p>{_escape_html(trimmed)}</p>')
    
    if in_list:
        html_parts.append('</ul>')
    
    return '<article>' + ''.join(html_parts) + '</article>'


def _final_cleanup(html_content: str) -> str:
    """Final cleanup of HTML content"""
    # Remove extra whitespace between tags
    html_content = re.sub(r'>\s+<', '><', html_content)
    # Fix multiple br tags (max 2 consecutive)
    html_content = re.sub(r'(<br\s*/?>){3,}', '<br><br>', html_content)
    # Remove leading/trailing whitespace
    html_content = html_content.strip()
    
    return html_content


def _has_structure(html_content: str) -> bool:
    """Check if content has structural elements"""
    structure_tags = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'ul', 'ol', 'table']
    return any(f'<{tag}' in html_content.lower() for tag in structure_tags)


def _escape_html(text: str) -> str:
    """Escape HTML special characters"""
    return (text
            .replace('&', '&amp;')
            .replace('<', '&lt;')
            .replace('>', '&gt;')
            .replace('"', '&quot;')
            .replace("'", '&#x27;'))

