"""
pdf_exporter.py — Export a TechnicalFile to PDF via Jinja2 + weasyprint.

Primary renderer: weasyprint (pure Python).
Fallback renderer: wkhtmltopdf (if weasyprint is not installed).

Usage::

    from sichgate.pdf_exporter import PDFExporter
    from sichgate.technical_file_builder import TechnicalFileBuilder

    builder = TechnicalFileBuilder(findings=findings, aibom=aibom)
    tf = builder.build()

    exporter = PDFExporter()
    path = exporter.export_pdf(tf, "/tmp/technical_file.pdf")
"""
from __future__ import annotations

import os
import subprocess
import tempfile
from pathlib import Path
from typing import TYPE_CHECKING

from jinja2 import Environment, FileSystemLoader, select_autoescape

if TYPE_CHECKING:
    from sichgate.technical_file_builder import TechnicalFile

# ---------------------------------------------------------------------------
# Template resolution
# ---------------------------------------------------------------------------

_TEMPLATE_DIR = Path(__file__).parent / "templates"
_TEMPLATE_NAME = "technical_file.html"


def _get_jinja_env() -> Environment:
    """Return a configured Jinja2 environment pointing at the template directory."""
    return Environment(
        loader=FileSystemLoader(str(_TEMPLATE_DIR)),
        autoescape=select_autoescape(["html"]),
        keep_trailing_newline=True,
    )


# ---------------------------------------------------------------------------
# Renderer detection
# ---------------------------------------------------------------------------

def _weasyprint_available() -> bool:
    try:
        import weasyprint  # noqa: F401
        return True
    except ImportError:
        return False


def _wkhtmltopdf_available() -> bool:
    try:
        result = subprocess.run(
            ["wkhtmltopdf", "--version"],
            capture_output=True,
            timeout=5,
        )
        return result.returncode == 0
    except (FileNotFoundError, subprocess.TimeoutExpired):
        return False


# ---------------------------------------------------------------------------
# PDFExporter
# ---------------------------------------------------------------------------

class PDFExporter:
    """
    Renders a :class:`~sichgate.technical_file_builder.TechnicalFile` to PDF.

    Renderer priority:
    1. ``weasyprint`` — installed as ``pip install weasyprint``
    2. ``wkhtmltopdf`` — system binary fallback

    Args:
        template_dir: Override the default templates directory (for testing).
    """

    def __init__(self, template_dir: str | None = None) -> None:
        tdir = Path(template_dir) if template_dir else _TEMPLATE_DIR
        self._env = Environment(
            loader=FileSystemLoader(str(tdir)),
            autoescape=select_autoescape(["html"]),
            keep_trailing_newline=True,
        )

    # ------------------------------------------------------------------
    # Public API
    # ------------------------------------------------------------------

    def render_html(self, technical_file: "TechnicalFile") -> str:
        """Render the Jinja2 template to an HTML string."""
        template = self._env.get_template(_TEMPLATE_NAME)
        return template.render(tf=technical_file)

    def export_pdf(self, technical_file: "TechnicalFile", output_path: str) -> str:
        """
        Render the Technical File to PDF and save it at ``output_path``.

        Also saves:
        - ``{output_path}.html`` — the intermediate HTML artefact
        - Returns the resolved path of the saved PDF.

        Raises:
            RuntimeError: If neither weasyprint nor wkhtmltopdf is available.
        """
        html_content = self.render_html(technical_file)

        output = Path(output_path)
        output.parent.mkdir(parents=True, exist_ok=True)

        # Save HTML artefact alongside the PDF
        html_path = output.with_suffix(".html")
        html_path.write_text(html_content, encoding="utf-8")

        if _weasyprint_available():
            self._render_weasyprint(html_content, str(output))
        elif _wkhtmltopdf_available():
            self._render_wkhtmltopdf(html_path, str(output))
        else:
            raise RuntimeError(
                "No PDF renderer available. Install weasyprint: pip install weasyprint"
            )

        return str(output)

    # ------------------------------------------------------------------
    # Renderers
    # ------------------------------------------------------------------

    @staticmethod
    def _render_weasyprint(html: str, output_path: str) -> None:
        import weasyprint  # type: ignore
        weasyprint.HTML(string=html).write_pdf(output_path)

    @staticmethod
    def _render_wkhtmltopdf(html_path: Path, output_path: str) -> None:
        cmd = [
            "wkhtmltopdf",
            "--quiet",
            "--page-size", "A4",
            "--margin-top", "25mm",
            "--margin-bottom", "30mm",
            "--margin-left", "20mm",
            "--margin-right", "20mm",
            "--footer-center", "[page] of [topage]",
            "--footer-font-size", "7",
            str(html_path),
            output_path,
        ]
        result = subprocess.run(cmd, capture_output=True, timeout=60)
        if result.returncode != 0:
            raise RuntimeError(
                f"wkhtmltopdf failed (exit {result.returncode}): "
                f"{result.stderr.decode(errors='replace')}"
            )
