"""
HTML-based Frame Generator Service

Renders HTML templates to frame images with variable substitution

Linux Environment Requirements:
    - fontconfig package must be installed
    - Basic fonts (e.g., fonts-liberation, fonts-noto) recommended
    
    Ubuntu/Debian: sudo apt-get install -y fontconfig fonts-liberation fonts-noto-cjk
    CentOS/RHEL: sudo yum install -y fontconfig liberation-fonts google-noto-cjk-fonts
"""

import os
import uuid
from typing import Dict, Any, Optional
from pathlib import Path
from html2image import Html2Image
from loguru import logger


class HTMLFrameGenerator:
    """
    HTML-based frame generator
    
    Renders HTML templates to frame images with variable substitution.
    Users can create custom templates using any HTML/CSS.
    
    Usage:
        >>> generator = HTMLFrameGenerator("templates/modern.html")
        >>> frame_path = await generator.generate_frame(
        ...     topic="Why reading matters",
        ...     text="Reading builds new neural pathways...",
        ...     image="/path/to/image.png",
        ...     ext={"content_title": "Sample Title", "content_author": "Author Name"}
        ... )
    """
    
    def __init__(self, template_path: str):
        """
        Initialize HTML frame generator
        
        Args:
            template_path: Path to HTML template file
        """
        self.template_path = template_path
        self.template = self._load_template(template_path)
        self.hti = None  # Lazy init to avoid overhead
        self._check_linux_dependencies()
        logger.debug(f"Loaded HTML template: {template_path}")
    
    def _check_linux_dependencies(self):
        """Check Linux system dependencies and warn if missing"""
        if os.name != 'posix':
            return
        
        try:
            import subprocess
            
            # Check fontconfig
            result = subprocess.run(
                ['fc-list'], 
                capture_output=True, 
                timeout=2
            )
            
            if result.returncode != 0:
                logger.warning(
                    "⚠️  fontconfig not found or not working properly. "
                    "Install with: sudo apt-get install -y fontconfig fonts-liberation fonts-noto-cjk"
                )
            elif not result.stdout:
                logger.warning(
                    "⚠️  No fonts detected by fontconfig. "
                    "Install fonts with: sudo apt-get install -y fonts-liberation fonts-noto-cjk"
                )
            else:
                logger.debug(f"✓ Fontconfig detected {len(result.stdout.splitlines())} fonts")
                
        except FileNotFoundError:
            logger.warning(
                "⚠️  fontconfig (fc-list) not found on system. "
                "Install with: sudo apt-get install -y fontconfig"
            )
        except Exception as e:
            logger.debug(f"Could not check fontconfig status: {e}")
    
    def _load_template(self, template_path: str) -> str:
        """Load HTML template from file"""
        path = Path(template_path)
        if not path.exists():
            raise FileNotFoundError(f"Template not found: {template_path}")
        
        with open(path, 'r', encoding='utf-8') as f:
            content = f.read()
        
        logger.debug(f"Template loaded: {len(content)} chars")
        return content
    
    def _find_chrome_executable(self) -> Optional[str]:
        """
        Find suitable Chrome/Chromium executable, preferring non-snap versions
        
        Returns:
            Path to Chrome executable or None to use default
        """
        if os.name != 'posix':
            return None
        
        import subprocess
        
        # Preferred browsers (non-snap versions)
        candidates = [
            '/usr/bin/google-chrome',
            '/usr/bin/google-chrome-stable',
            '/usr/bin/chromium',
            '/usr/bin/chromium-browser',
            '/usr/local/bin/chrome',
            '/usr/local/bin/chromium',
        ]
        
        # Check each candidate
        for path in candidates:
            if os.path.exists(path) and os.access(path, os.X_OK):
                try:
                    # Verify it's not a snap by checking the path
                    result = subprocess.run(
                        ['readlink', '-f', path],
                        capture_output=True,
                        text=True,
                        timeout=1
                    )
                    real_path = result.stdout.strip()
                    
                    if '/snap/' not in real_path:
                        logger.info(f"✓ Found non-snap browser: {path} -> {real_path}")
                        return path
                    else:
                        logger.debug(f"✗ Skipping snap browser: {path}")
                except Exception as e:
                    logger.debug(f"Error checking {path}: {e}")
        
        # Warn if no suitable browser found
        logger.warning(
            "⚠️  No non-snap Chrome/Chromium found. Snap browsers have AppArmor restrictions.\n"
            "   Install system Chrome with:\n"
            "   wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb\n"
            "   sudo dpkg -i google-chrome-stable_current_amd64.deb\n"
            "   Or install Chromium: sudo apt-get install -y chromium-browser"
        )
        return None
    
    def _ensure_hti(self, width: int, height: int):
        """Lazily initialize Html2Image instance"""
        if self.hti is None:
            # Configure Chrome flags for Linux headless environment
            custom_flags = [
                '--no-sandbox',  # Bypass AppArmor/sandbox restrictions
                '--disable-dev-shm-usage',  # Avoid shared memory issues
                '--disable-gpu',  # Disable GPU acceleration
                '--disable-software-rasterizer',  # Disable software rasterizer
                '--disable-extensions',  # Disable extensions
                '--disable-setuid-sandbox',  # Additional sandbox bypass
                '--disable-dbus',  # Disable DBus to avoid permission errors
                '--hide-scrollbars',  # Hide scrollbars for cleaner output
                '--mute-audio',  # Mute audio
                '--disable-background-networking',  # Disable background networking
                '--disable-features=TranslateUI',  # Disable translate UI
                '--disable-ipc-flooding-protection',  # Improve performance
                '--no-first-run',  # Skip first run dialogs
                '--no-default-browser-check',  # Skip default browser check
                '--disable-backgrounding-occluded-windows',  # Improve performance
                '--disable-renderer-backgrounding',  # Improve performance
            ]
            
            # Try to find non-snap browser
            browser_path = self._find_chrome_executable()
            
            kwargs = {
                'size': (width, height),
                'custom_flags': custom_flags
            }
            
            if browser_path:
                kwargs['browser_executable'] = browser_path
            
            self.hti = Html2Image(**kwargs)
            
            if browser_path:
                logger.debug(f"Initialized Html2Image with size ({width}, {height}), {len(custom_flags)} custom flags, using browser: {browser_path}")
            else:
                logger.debug(f"Initialized Html2Image with size ({width}, {height}) and {len(custom_flags)} custom flags")
    
    async def generate_frame(
        self,
        title: str,
        text: str,
        image: str,
        ext: Optional[Dict[str, Any]] = None,
        width: int = 1080,
        height: int = 1920
    ) -> str:
        """
        Generate frame from HTML template
        
        Args:
            title: Video title
            text: Narration text for this frame
            image: Path to AI-generated image
            ext: Additional data (content_title, content_author, etc.)
            width: Frame width in pixels
            height: Frame height in pixels
        
        Returns:
            Path to generated frame image
        """
        # Build variable context
        context = {
            # Required variables
            "title": title,
            "text": text,
            "image": image,
        }
        
        # Add all ext fields
        if ext:
            context.update(ext)
        
        # Replace variables in HTML
        html = self.template
        for key, value in context.items():
            placeholder = f"{{{{{key}}}}}"
            html = html.replace(placeholder, str(value) if value is not None else "")
        
        # Generate unique output path
        from reelforge.utils.os_util import get_output_path
        output_filename = f"frame_{uuid.uuid4().hex[:16]}.png"
        output_path = get_output_path(output_filename)
        
        # Ensure Html2Image is initialized
        self._ensure_hti(width, height)
        
        # Render HTML to image
        logger.debug(f"Rendering HTML template to {output_path}")
        try:
            self.hti.screenshot(
                html_str=html,
                save_as=output_filename,
                size=(width, height)
            )
            
            # html2image saves to current directory by default, move to output
            import os
            import shutil
            if os.path.exists(output_filename):
                shutil.move(output_filename, output_path)
            
            logger.info(f"✅ Frame generated: {output_path}")
            return output_path
            
        except Exception as e:
            logger.error(f"Failed to render HTML template: {e}")
            raise RuntimeError(f"HTML rendering failed: {e}")

