"""
PDF generation service using WeasyPrint.

Based on deep research findings, WeasyPrint is the optimal choice for
production Flask applications due to:
- Pure Python (no external binaries except Pango)
- Modern CSS3 support
- Active maintenance (v66.0 as of July 2025)
- Good paged media features
"""

import io
from html import escape
from typing import Optional, Dict, Any
import markdown  # type: ignore[import-untyped]
from weasyprint import HTML, CSS
from loguru import logger


class PDFService:
    """Service for converting markdown to PDF using WeasyPrint."""

    def __init__(self):
        """Initialize PDF service with minimal CSS for readability."""
        self.minimal_css = CSS(
            string="""
            @page {
                size: A4;
                margin: 1.5cm;
            }

            body {
                font-family: Arial, sans-serif;
                font-size: 10pt;
                line-height: 1.4;
            }

            table {
                border-collapse: collapse;
                width: 100%;
                margin: 0.5em 0;
            }

            th, td {
                border: 1px solid #ccc;
                padding: 6px;
                text-align: left;
            }

            th {
                background-color: #f0f0f0;
            }

            h1 { font-size: 16pt; margin: 0.5em 0; }
            h2 { font-size: 14pt; margin: 0.5em 0; }
            h3 { font-size: 12pt; margin: 0.5em 0; }
            h4 { font-size: 11pt; margin: 0.5em 0; font-weight: bold; }
            h5 { font-size: 10pt; margin: 0.5em 0; font-weight: bold; }
            h6 { font-size: 10pt; margin: 0.5em 0; }

            code {
                font-family: monospace;
                background-color: #f5f5f5;
                padding: 1px 3px;
            }

            pre {
                background-color: #f5f5f5;
                padding: 8px;
                overflow-x: auto;
            }

            a {
                color: #0066cc;
                text-decoration: none;
            }
        """
        )

    def markdown_to_pdf(
        self,
        markdown_content: str,
        title: Optional[str] = None,
        metadata: Optional[Dict[str, Any]] = None,
        custom_css: Optional[str] = None,
    ) -> bytes:
        """
        Convert markdown content to PDF.

        Args:
            markdown_content: The markdown text to convert
            title: Optional title for the document
            metadata: Optional metadata dict (author, date, etc.)
            custom_css: Optional CSS string to override defaults

        Returns:
            PDF file as bytes

        Note:
            WeasyPrint memory usage can spike with large documents.
            Production deployments should implement:
            - Memory limits (ulimit)
            - Timeouts (30-60 seconds)
            - Worker recycling after 100 requests
        """
        try:
            # Convert markdown to HTML
            html_content = self._markdown_to_html(
                markdown_content, title, metadata
            )

            # Create HTML document with WeasyPrint
            html_doc = HTML(string=html_content)

            # Apply CSS (custom or minimal default)
            css_list = []
            if custom_css:
                css_list.append(CSS(string=custom_css))
            else:
                css_list.append(self.minimal_css)

            # Generate PDF
            # Use BytesIO to get bytes instead of writing to file
            pdf_buffer = io.BytesIO()
            html_doc.write_pdf(pdf_buffer, stylesheets=css_list)

            # Get the PDF bytes
            pdf_bytes = pdf_buffer.getvalue()
            pdf_buffer.close()

            logger.info(f"Generated PDF, size: {len(pdf_bytes)} bytes")
            return pdf_bytes

        except Exception:
            logger.exception("Error generating PDF")
            raise

    def _markdown_to_html(
        self,
        markdown_content: str,
        title: Optional[str] = None,
        metadata: Optional[Dict[str, Any]] = None,
    ) -> str:
        """
        Convert markdown to HTML with proper structure.

        Uses Python-Markdown with extensions for:
        - Tables
        - Fenced code blocks
        - Table of contents
        - Footnotes
        """
        # Parse markdown with extensions
        md = markdown.Markdown(
            extensions=[
                "tables",
                "fenced_code",
                "footnotes",
                "toc",
                "nl2br",  # Convert newlines to <br>
                "sane_lists",
                "meta",
            ]
        )

        html_body = md.convert(markdown_content)

        # Build complete HTML document
        html_parts = ["<!DOCTYPE html><html><head>"]
        html_parts.append('<meta charset="utf-8">')

        if title:
            html_parts.append(f"<title>{escape(title)}</title>")

        if metadata:
            for key, value in metadata.items():
                html_parts.append(
                    f'<meta name="{escape(str(key))}" content="{escape(str(value))}">'
                )

        html_parts.append("</head><body>")

        # Add the markdown content directly without any extra title or metadata
        html_parts.append(html_body)

        # Add footer with LDR attribution
        html_parts.append("""
            <div style="margin-top: 2em; padding-top: 1em; border-top: 1px solid #ddd; font-size: 9pt; color: #666; text-align: center;">
                Generated by <a href="https://github.com/LearningCircuit/local-deep-research" style="color: #0066cc;">LDR - Local Deep Research</a> | Open Source AI Research Assistant
            </div>
        """)

        html_parts.append("</body></html>")

        return "".join(html_parts)


# Singleton instance
_pdf_service = None


def get_pdf_service() -> PDFService:
    """Get or create the PDF service singleton."""
    global _pdf_service
    if _pdf_service is None:
        _pdf_service = PDFService()
    return _pdf_service
