"""Core conversion logic for markdown to PDF."""

import importlib.resources
import os
import re
import shutil
import subprocess
import tempfile
import time
from pathlib import Path

from playwright.sync_api import sync_playwright


def _get_template_content() -> str:
    """Load the mkdocs.yml template from package resources."""
    return importlib.resources.files("mkdocs_md_to_pdf").joinpath(
        "mkdocs.yml.template"
    ).read_text()


def _create_temp_mkdocs_config(input_file: Path, temp_dir: Path) -> Path:
    """Create a temporary mkdocs.yml configuration for the specified file."""
    template_content = _get_template_content()

    temp_docs_dir = temp_dir / "docs"
    temp_docs_dir.mkdir(parents=True, exist_ok=True)

    temp_file_path = temp_docs_dir / "index.md"
    shutil.copy2(input_file, temp_file_path)

    # Extract and copy linked files
    linked_files = _extract_linked_files(input_file)
    for linked_file in linked_files:
        linked_file_path = input_file.parent / linked_file
        if linked_file_path.is_file():
            shutil.copy2(linked_file_path, temp_docs_dir)

    config_content = template_content.replace(
        "{{site_name}}", input_file.name
    ).replace("{{docs_dir}}", "docs")

    temp_config_path = temp_dir / "mkdocs.yml"
    temp_config_path.write_text(config_content)

    return temp_config_path


def _extract_linked_files(input_file: Path) -> list[str]:
    """Extract relative file links from markdown content."""
    content = input_file.read_text()
    linked_files = []

    link_re = re.compile(r"\[.*?]\((.*?)\)")
    image_tag_re = re.compile(r'<img.*?src="(.*?)".*?>')

    for match in link_re.findall(content):
        if not match.startswith(("http", "#")):
            linked_files.append(match)

    for match in image_tag_re.findall(content):
        if not match.startswith("http"):
            linked_files.append(match)

    return linked_files


def _serve_mkdocs(temp_dir: Path, port: int = 8765) -> subprocess.Popen:
    """Build and serve the mkdocs site."""
    subprocess.run(["mkdocs", "build"], cwd=temp_dir, check=True, capture_output=True)

    server_process = subprocess.Popen(
        ["mkdocs", "serve", "-a", f"127.0.0.1:{port}"],
        cwd=temp_dir,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
    )

    time.sleep(2)
    return server_process


def _generate_pdf_bytes(port: int = 8765) -> bytes:
    """Use Playwright to render the served page to PDF."""
    with sync_playwright() as p:
        browser = p.chromium.launch()
        page = browser.new_page()
        page.goto(f"http://127.0.0.1:{port}/")
        page.wait_for_load_state("load")
        page.wait_for_function("() => document.fonts.ready")

        pdf_bytes = page.pdf(
            print_background=True,
            margin={
                "top": "0.4in",
                "right": "0.4in",
                "bottom": "0.4in",
                "left": "0.4in",
            },
            display_header_footer=False,
        )

        browser.close()
        return pdf_bytes


def convert(input_file: str | Path, output_file: str | Path | None = None) -> bytes:
    """
    Convert a markdown file to PDF.

    Args:
        input_file: Path to the markdown file to convert.
        output_file: Optional path to write the PDF. If None, returns bytes only.

    Returns:
        The PDF content as bytes.

    Raises:
        FileNotFoundError: If the input file does not exist.
    """
    input_path = Path(input_file).resolve()

    if not input_path.is_file():
        raise FileNotFoundError(f"File not found: {input_path}")

    with tempfile.TemporaryDirectory() as temp_dir:
        temp_path = Path(temp_dir)
        _create_temp_mkdocs_config(input_path, temp_path)
        server_process = _serve_mkdocs(temp_path)

        try:
            pdf_bytes = _generate_pdf_bytes()
        finally:
            server_process.terminate()
            server_process.wait()

    if output_file:
        Path(output_file).write_bytes(pdf_bytes)

    return pdf_bytes
