"""Tests for the HTML template system."""

import tempfile
from pathlib import Path

import pytest

from nhandu import execute, parse, render
from nhandu.models import DocumentMetadata
from nhandu.templates import Template, get_template, list_templates

# --- Registry tests ---


def test_default_template_registered():
    """Default template is registered with non-empty CSS."""
    t = get_template("default")
    assert isinstance(t, Template)
    assert t.name == "default"
    assert len(t.css) > 100
    assert "font-family" in t.css


def test_academic_template_registered():
    """Academic template has serif fonts."""
    t = get_template("academic")
    assert isinstance(t, Template)
    assert t.name == "academic"
    assert "Georgia" in t.css
    assert "serif" in t.css


def test_corporate_template_registered():
    """Corporate template has blue accents."""
    t = get_template("corporate")
    assert isinstance(t, Template)
    assert t.name == "corporate"
    assert "#0366d6" in t.css


def test_list_templates_returns_all():
    """list_templates returns all three built-in templates."""
    templates = list_templates()
    names = [t.name for t in templates]
    assert "default" in names
    assert "academic" in names
    assert "corporate" in names
    assert len(templates) >= 3


def test_list_templates_sorted():
    """Templates are returned sorted by name."""
    templates = list_templates()
    names = [t.name for t in templates]
    assert names == sorted(names)


def test_unknown_template_raises():
    """Unknown template name raises ValueError with available names."""
    with pytest.raises(ValueError, match="Unknown template 'nonexistent'"):
        get_template("nonexistent")


def test_unknown_template_lists_available():
    """Error message lists available template names."""
    with pytest.raises(ValueError, match="default"):
        get_template("nonexistent")


def test_template_is_frozen():
    """Template dataclass is immutable."""
    t = get_template("default")
    with pytest.raises(AttributeError):
        t.name = "modified"


# --- Metadata integration tests ---


def test_template_metadata_default_none():
    """DocumentMetadata has template=None by default."""
    meta = DocumentMetadata()
    assert meta.template is None
    assert meta.template_css is None


def test_template_metadata_from_dict():
    """from_dict correctly sets template field."""
    meta = DocumentMetadata.from_dict({"template": "academic"})
    assert meta.template == "academic"


def test_template_css_metadata_from_dict():
    """from_dict correctly sets template_css field."""
    meta = DocumentMetadata.from_dict({"template_css": "/path/to/custom.css"})
    assert meta.template_css == "/path/to/custom.css"


# --- Rendering integration tests ---


def test_render_with_default_template():
    """Default template renders with sans-serif CSS."""
    content = "#' # Hello\n\nprint('hi')"
    doc = parse(content)
    executed = execute(doc)
    html = render(executed, format="html")
    assert "font-family" in html
    assert ".code-block" in html
    assert ".nhandu-footer" in html


def test_render_with_academic_template():
    """Academic template renders with serif fonts."""
    content = "#' ---\n#' template: academic\n#' ---\n#' # Hello\n\nprint('hi')"
    doc = parse(content)
    executed = execute(doc)
    html = render(executed, format="html")
    assert "Georgia" in html
    assert "serif" in html


def test_render_with_corporate_template():
    """Corporate template renders with blue accents."""
    content = "#' ---\n#' template: corporate\n#' ---\n#' # Hello\n\nprint('hi')"
    doc = parse(content)
    executed = execute(doc)
    html = render(executed, format="html")
    assert "#0366d6" in html


def test_pygments_css_always_injected():
    """Pygments CSS is present regardless of template."""
    for name in ("default", "academic", "corporate"):
        content = f"#' ---\n#' template: {name}\n#' ---\n#' # Test\n\nx = 1"
        doc = parse(content)
        executed = execute(doc)
        html = render(executed, format="html")
        assert ".highlight" in html, f"Pygments CSS missing for template '{name}'"


def test_template_does_not_affect_markdown_output():
    """Template setting is ignored for markdown output."""
    content = "#' ---\n#' template: corporate\n#' ---\n#' # Hello\n\nprint('hi')"
    doc = parse(content)
    executed = execute(doc)
    md = render(executed, format="markdown")
    # Markdown output should not contain CSS
    assert "#0366d6" not in md
    assert "Georgia" not in md


def test_all_templates_have_required_classes():
    """Every built-in template defines all required CSS classes."""
    required = [
        ".code-block",
        ".code-input",
        ".code-output",
        ".error",
        ".nhandu-footer",
    ]
    for t in list_templates():
        for cls in required:
            assert cls in t.css, f"Template '{t.name}' missing CSS class '{cls}'"


def test_custom_css_file():
    """Custom CSS file is appended to template CSS."""
    with tempfile.NamedTemporaryFile(mode="w", suffix=".css", delete=False) as f:
        f.write(".custom-class { color: magenta; }")
        f.flush()
        css_path = f.name

    content = "#' # Hello\n\nprint('hi')"
    doc = parse(content)
    doc.metadata.template_css = css_path
    executed = execute(doc)
    html = render(executed, format="html")
    assert ".custom-class" in html
    assert "magenta" in html

    Path(css_path).unlink()


def test_custom_css_with_template():
    """Custom CSS works alongside a specific template."""
    with tempfile.NamedTemporaryFile(mode="w", suffix=".css", delete=False) as f:
        f.write("body { border: 1px solid red; }")
        f.flush()
        css_path = f.name

    content = "#' ---\n#' template: academic\n#' ---\n#' # Hello\n\nprint('hi')"
    doc = parse(content)
    doc.metadata.template_css = css_path
    executed = execute(doc)
    html = render(executed, format="html")
    # Both academic CSS and custom CSS should be present
    assert "Georgia" in html
    assert "border: 1px solid red" in html

    Path(css_path).unlink()


def test_custom_css_relative_to_source_path(tmp_path: Path) -> None:
    """Relative template_css paths should resolve from the document directory."""
    css_path = tmp_path / "styles.css"
    css_path.write_text("body { color: teal; }", encoding="utf-8")

    content = (
        "#' ---\n#' output: html\n#' template_css: styles.css\n#' ---\n#' # Hello\n"
    )

    doc_path = tmp_path / "report.py"
    doc = parse(content, str(doc_path))
    doc.source_path = doc_path
    executed = execute(doc)
    html = render(executed, format="html")

    assert "color: teal" in html


def test_invalid_template_name_in_render():
    """Invalid template name raises ValueError during rendering."""
    content = "#' # Hello\n\nprint('hi')"
    doc = parse(content)
    doc.metadata.template = "nonexistent"
    executed = execute(doc)
    with pytest.raises(ValueError, match="Unknown template"):
        render(executed, format="html")
