import os
import tempfile
import logging
import io
from typing import Tuple, Optional, Dict, Any
from PIL import Image, ImageDraw, ImageFont
import re

from .base import Component

try:
    from selenium import webdriver
    from selenium.webdriver.chrome.options import Options
    from selenium.webdriver.chrome.service import Service
    from webdriver_manager.chrome import ChromeDriverManager

    SELENIUM_AVAILABLE = True
except ImportError:
    SELENIUM_AVAILABLE = False

logger = logging.getLogger(__name__)


class HTMLComponent(Component):
    """Component for rendering HTML/CSS content onto an image."""

    def __init__(
        self,
        html_content: str,
        css_content: Optional[str] = None,
        position: Tuple[int, int] = (0, 0),
        size: Tuple[int, int] = (800, 600),
        background_transparent: bool = False,
        rendering_engine: str = "auto",
        variables: Optional[Dict[str, Any]] = None,
        add_default_styles: bool = False,  # NEW PARAMETER
    ):
        super().__init__(position)
        self.html_content = html_content
        self.css_content = css_content or ""
        self.size = size
        self.background_transparent = background_transparent
        self.variables = variables or {}
        self.add_default_styles = add_default_styles  # NEW ATTRIBUTE
        self.rendering_engine = (
            "auto"
            if rendering_engine not in ["selenium", "pil", "auto"]
            else rendering_engine
        )

    def render(self, image: Image.Image) -> Image.Image:
        if not self.html_content:
            return image
        html_image = self._render_html_to_image()
        if html_image:
            image.paste(
                html_image,
                self.position,
                html_image if html_image.mode == "RGBA" else None,
            )
        return image

    def _render_html_to_image(self) -> Optional[Image.Image]:
        if self.rendering_engine == "pil" or (
            self.rendering_engine == "auto" and not SELENIUM_AVAILABLE
        ):
            return self._render_with_pil_fallback()
        if SELENIUM_AVAILABLE:
            return self._render_with_selenium()
        logger.warning("Selenium unavailable. Falling back to PIL renderer.")
        return self._render_with_pil_fallback()

    def _render_with_selenium(self) -> Optional[Image.Image]:
        try:
            with tempfile.NamedTemporaryFile(
                suffix=".html", delete=False, mode="w", encoding="utf-8"
            ) as f:
                f.write(self._create_full_html())
                html_file = f.name

            chrome_options = Options()
            chrome_options.add_argument("--headless")
            chrome_options.add_argument("--no-sandbox")
            chrome_options.add_argument("--disable-dev-shm-usage")
            if self.background_transparent:
                chrome_options.add_argument("--disable-background-timer-throttling")
            driver = webdriver.Chrome(
                service=Service(ChromeDriverManager().install()), options=chrome_options
            )
            driver.set_window_size(*self.size)
            driver.get(f"file://{html_file}")

            # Only apply default styles if add_default_styles is True
            if self.add_default_styles:
                driver.execute_script(
                    f"document.body.style.margin = '0'; document.body.style.padding = '0';"
                )

            screenshot = driver.get_screenshot_as_png()
            driver.quit()
            os.unlink(html_file)
            return Image.open(io.BytesIO(screenshot)).crop(
                (0, 0, self.size[0], self.size[1])
            )

        except Exception as e:
            logger.error(f"Selenium rendering failed: {e}")
            return None

    def _render_with_pil_fallback(self) -> Image.Image:
        try:
            img = Image.new(
                "RGBA",
                self.size,
                (0, 0, 0, 0) if self.background_transparent else (255, 255, 255, 255),
            )
            draw = ImageDraw.Draw(img)
            text_content = self._extract_text_from_html(
                self._substitute_variables(self.html_content)
            )
            font = ImageFont.load_default()
            margin, line_height = 20, 20
            x, y = margin, margin
            max_width = self.size[0] - 2 * margin

            if "title" in self.variables:
                draw.text(
                    (x, y), str(self.variables["title"]), fill=(0, 0, 0), font=font
                )
                y += 34
            if "subtitle" in self.variables:
                draw.text(
                    (x, y), str(self.variables["subtitle"]), fill=(0, 0, 0), font=font
                )
                y += 28
            lines = []
            line = ""
            for word in text_content.split():
                test_line = f"{line}{word} "
                if draw.textlength(test_line, font=font) <= max_width:
                    line = test_line
                else:
                    lines.append(line)
                    line = f"{word} "
            if line:
                lines.append(line)
            for line in lines:
                draw.text((x, y), line, fill=(0, 0, 0), font=font)
                y += line_height
            return img
        except Exception as e:
            logger.error(f"PIL rendering failed: {e}")
            return Image.new("RGBA", self.size, (255, 255, 255, 255))

    def _extract_text_from_html(self, html_content: str) -> str:
        text = re.sub(r"<[^>]*>", " ", html_content)
        text = (
            text.replace("&nbsp;", " ")
            .replace("&amp;", "&")
            .replace("&lt;", "<")
            .replace("&gt;", ">")
        )
        text = text.replace("&quot;", '"').replace("&#39;", "'")
        return re.sub(r"\s+", " ", text).strip()

    def _create_full_html(self) -> str:
        processed_html = self._substitute_variables(self.html_content)
        style_content = self._substitute_variables(self.css_content)

        # Only add default body styles if add_default_styles is True
        default_body_styles = ""
        if self.add_default_styles:
            background = "transparent" if self.background_transparent else "#000"
            default_body_styles = f"margin: 0; padding: 0; width: {self.size[0]}px; height: {self.size[1]}px; background: {background}; overflow: hidden;"

        return f"""
        <!DOCTYPE html>
        <html>
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width={self.size[0]}, height={self.size[1]}, initial-scale=1.0">
            <style>
                body {{ {default_body_styles} }}
                {style_content}
            </style>
        </head>
        <body>
            {processed_html}
        </body>
        </html>
        """

    def _substitute_variables(self, content: str) -> str:
        if not content or not self.variables:
            return content
        return re.sub(
            r"\${([^}]+)}",
            lambda m: str(self.variables.get(m.group(1), m.group(0))),
            content,
        )

    @classmethod
    def from_config(cls, config: Dict[str, Any]) -> "HTMLComponent":
        position = (
            config.get("position", {}).get("x", 0),
            config.get("position", {}).get("y", 0),
        )
        size = (
            config.get("size", {}).get("width", 800),
            config.get("size", {}).get("height", 600),
        )
        return cls(
            html_content=config.get("html_content", ""),
            css_content=config.get("css_content"),
            position=position,
            size=size,
            background_transparent=config.get("background_transparent", False),
            rendering_engine=config.get("rendering_engine", "auto"),
            variables=config.get("variables", {}),
            add_default_styles=config.get("add_default_styles", False),  # NEW PARAMETER
        )
