from datetime import datetime
from typing import List

from abs_utils.logger import setup_logger
from bs4 import BeautifulSoup, NavigableString
from jinja2 import Environment, FileSystemLoader, select_autoescape

logger = setup_logger(__name__)


class TemplateService:
    """Service for rendering email templates using Jinja2."""

    def __init__(self, template_dir: str):
        """
        Initialize the template service.

        Args:
            template_dir: Directory containing template files.
        """
        self.template_dir = template_dir
        self.env = Environment(
            loader=FileSystemLoader(template_dir),
            autoescape=select_autoescape(["html", "xml"]),
        )

    def render_template(self, template_name: str, **kwargs) -> str:
        """
        Render a template with the provided variables.

        Args:
            template_name: Name of the template file
            **kwargs: Variables to pass to the template

        Returns:
            Rendered template as string
        """
        try:
            template = self.env.get_template(template_name)

            # Add default timestamp if not provided
            if "timestamp" not in kwargs:
                kwargs["timestamp"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")

            return template.render(**kwargs)

        except Exception as e:
            logger.error(f"Error rendering template {template_name}: {str(e)}")
            raise

    def _parse_emails(self, value) -> List[str]:
        """Parse email addresses from a string or list."""
        if isinstance(value, str):
            return [e.strip() for e in value.replace('\n', ',').split(',') if e.strip()]
        if isinstance(value, list):
            return value
        return []

    def _sanitize_quill_html(self, html: str) -> str:
        """Sanitize Quill editor HTML output to fix structural issues.

        Uses BeautifulSoup for reliable HTML parsing.

        Args:
            html: Raw HTML from Quill editor

        Returns:
            Sanitized HTML with proper structure
        """
        if not html:
            return html

        soup = BeautifulSoup(html, 'html.parser')

        # 1. Remove all ql-ui spans
        for span in soup.find_all('span', class_='ql-ui'):
            span.decompose()

        # 2. Normalize list tags based on data-list attribute
        #    Quill may wrap bullets in <ol> or ordered in <ul>
        #    Split mixed lists into separate correct tags
        for lst in list(soup.find_all(['ul', 'ol'])):
            items = lst.find_all('li', recursive=False)
            if not items:
                continue

            types = set()
            for li in items:
                dl = li.get('data-list', '')
                if dl == 'bullet':
                    types.add('ul')
                elif dl == 'ordered':
                    types.add('ol')
                else:
                    types.add(lst.name)

            if len(types) == 1:
                lst.name = types.pop()
            else:
                # Mixed list - split into groups by type
                groups = []
                current_type = None
                current_items = []
                for li in items:
                    dl = li.get('data-list', '')
                    li_type = 'ul' if dl == 'bullet' else 'ol' if dl == 'ordered' else lst.name
                    if li_type != current_type:
                        if current_items:
                            groups.append((current_type, current_items))
                        current_type = li_type
                        current_items = [li]
                    else:
                        current_items.append(li)
                if current_items:
                    groups.append((current_type, current_items))

                for tag_name, lis in reversed(groups):
                    new_list = soup.new_tag(tag_name)
                    for li in lis:
                        new_list.append(li.extract())
                    lst.insert_after(new_list)
                lst.decompose()

        # 3. Clean data-list attributes
        for li in soup.find_all('li'):
            if li.has_attr('data-list'):
                del li['data-list']

        # 4. Merge consecutive SAME-TYPE lists separated by <br> or whitespace
        for tag_name in ('ul', 'ol'):
            for lst in list(soup.find_all(tag_name)):
                if lst.parent is None:
                    continue
                while True:
                    next_sib = lst.next_sibling
                    nodes_to_remove = []
                    while next_sib and (
                        (isinstance(next_sib, NavigableString) and not str(next_sib).strip())
                        or getattr(next_sib, 'name', None) == 'br'
                    ):
                        nodes_to_remove.append(next_sib)
                        next_sib = next_sib.next_sibling
                    # Only merge if SAME tag type
                    if next_sib and getattr(next_sib, 'name', None) == tag_name:
                        for node in nodes_to_remove:
                            node.extract()
                        for li in list(next_sib.find_all('li', recursive=False)):
                            lst.append(li.extract())
                        next_sib.decompose()
                    else:
                        break

        # 5. Fix fragmented paragraphs like <p>Dear </p>Name<p>,</p>
        for p in list(soup.find_all('p')):
            next_sibling = p.next_sibling
            if isinstance(next_sibling, NavigableString) and str(next_sibling).strip():
                next_next = next_sibling.next_sibling
                if next_next and getattr(next_next, 'name', None) == 'p':
                    p.append(str(next_sibling).strip())
                    p.append(next_next.get_text())
                    next_sibling.extract()
                    next_next.decompose()

        return str(soup)

    def sanitize_quill_html(self, html: str) -> str:
        """
        Public method to sanitize Quill editor HTML output.

        Fixes common Quill structural issues:
        - Removes internal ql-ui spans
        - Normalizes list tags based on data-list attribute (bullet → ul, ordered → ol)
        - Splits mixed lists into separate correct tags
        - Merges consecutive same-type lists separated by whitespace or <br>
        - Cleans data-list attributes from li elements
        - Merges split paragraphs (e.g. ``<p>Dear </p>Name<p>,</p>`` → ``<p>Dear Name,</p>``)

        Args:
            html: Raw HTML from Quill editor

        Returns:
            Sanitized HTML with proper structure
        """
        return self._sanitize_quill_html(html)

    def render_email_template(
        self, title: str, content: str, sanitize_quill: bool = False, **kwargs
    ) -> str:
        """
        Render the email template with common variables.

        Args:
            title: Email title
            content: Email content (can be HTML)
            sanitize_quill: If True, sanitize Quill editor HTML before rendering.
                            Use this when content originates from a Quill rich-text editor.
            **kwargs: Additional template variables

        Returns:
            Rendered email HTML
        """
        if sanitize_quill:
            content = self._sanitize_quill_html(content)

        return self.render_template(
            "email_template.html", title=title, content=content, **kwargs
        )
