"""The Jinja template pack renders (M1 P4.1).

The pack ships as plain package data; consumers render it with THEIR Jinja.
These tests do exactly what a consumer does — FileSystemLoader over
``templates_dir()`` — and pin the pack's contract: the console shell renders
with its blocks, the macros emit the kit classes, icons reference the vendored
sprite with the canon a11y semantics. jinja2 is a dev-only extra; the package
itself imports no template engine (import-linter enforced).
"""

from __future__ import annotations

import re

import pytest
from jinja2 import ChoiceLoader, DictLoader, Environment, FileSystemLoader

from mgf.brand_web import static_dir, templates_dir


@pytest.fixture(scope="module")
def env() -> Environment:
    return Environment(loader=FileSystemLoader(str(templates_dir())), autoescape=True)


def _macros(env: Environment, call: str) -> str:
    """Render a single macro call against the shipped macro module."""
    tpl = env.from_string("{% import 'mgf/macros.html' as mgf %}{{ mgf." + call + " }}")
    return tpl.render()


# ---------------------------------------------------------------- the shell --


def test_console_shell_renders_standalone(env: Environment) -> None:
    html = env.get_template("mgf/console.html").render()
    for marker in (
        '<meta name="color-scheme" content="light dark">',
        'class="skip-link" href="#mgf-main"',
        'class="mgf-console"',
        'class="mgf-console__topbar"',
        'class="mgf-console__rail"',
        'id="mgf-main" class="mgf-console__main"',
        "/static/brand/console.css",
        "/static/brand/instruments.css",
        "/static/brand/logo/magogi-favicon.svg",
    ):
        assert marker in html, marker


def test_console_shell_extends_like_an_app(env: Environment) -> None:
    """The adoption pattern: an app base template overrides the blocks."""
    child = (
        '{% extends "mgf/console.html" %}'
        "{% block title %}my-console{% endblock %}"
        "{% block mark_title %}my-console{% endblock %}"
        "{% block mark_sub %}operator surface{% endblock %}"
        '{% block topbar %}<span id="t-actions">act</span>{% endblock %}'
        '{% block rail %}<a class="mgf-console__nav" href="/">home</a>{% endblock %}'
        "{% block main %}<h1>readout</h1>{% endblock %}"
        "{% block scripts %}<script>/*app*/</script>{% endblock %}"
    )
    app_env = Environment(
        loader=ChoiceLoader(
            [DictLoader({"base.html": child}), FileSystemLoader(str(templates_dir()))]
        ),
        autoescape=True,
    )
    html = app_env.get_template("base.html").render()
    assert "<title>my-console</title>" in html
    assert ">operator surface</span>" in html
    assert '<span id="t-actions">act</span>' in html
    assert '<a class="mgf-console__nav" href="/">home</a>' in html
    assert "<h1>readout</h1>" in html
    assert "<script>/*app*/</script>" in html
    # The shell chrome came from the kit, not the child.
    assert 'class="mgf-console__topbar"' in html
    assert 'class="skip-link" href="#mgf-main"' in html


# ------------------------------------------------------------------ macros --


def test_icon_is_decorative_by_default(env: Environment) -> None:
    html = _macros(env, "icon('check')")
    assert 'aria-hidden="true"' in html
    assert 'href="/static/brand/icons/icons-sprite.svg#mgf-icon-check"' in html
    assert 'class="mgf-icon"' in html
    assert "role=" not in html


def test_icon_named_when_meaningful(env: Environment) -> None:
    html = _macros(env, "icon('success', label='Verified')")
    assert 'role="img"' in html
    assert 'aria-label="Verified"' in html
    assert "aria-hidden" not in html


def test_icon_explicit_size_overrides_em_flow(env: Environment) -> None:
    html = _macros(env, "icon('kernel', size=24)")
    assert 'style="width:24px;height:24px"' in html


def test_sync_chip_states(env: Environment) -> None:
    html = _macros(env, "sync_chip('IN_SYNC')")
    assert "status-chip--in-sync" in html
    assert "status-chip__dot" in html
    assert ">IN_SYNC<" in html
    # in-flight states swap the dot for the spinner
    checking = _macros(env, "sync_chip('CHECKING')")
    assert '<span class="spinner"></span>' in checking
    assert "status-chip__dot" not in checking


def test_status_chip_running_override_and_default(env: Environment) -> None:
    assert "status-chip--running" in _macros(env, "status_chip('pass', running=true)")
    assert "status-chip--unknown" in _macros(env, "status_chip(none)")
    assert "status-chip--pass" in _macros(env, "status_chip('pass')")


def test_chips_take_optional_sprite_icons(env: Environment) -> None:
    html = _macros(env, "status_chip('fail', icon_name='error')")
    assert "#mgf-icon-error" in html
    assert 'aria-hidden="true"' in html  # decoration on top of dot + label
    assert "status-chip__dot" in html  # the dot stays
    html = _macros(env, "sync_chip('STALE', icon_name='warning')")
    assert "#mgf-icon-warning" in html and "status-chip--stale" in html


def test_tstate_kebabs_the_class_and_deunderscores_the_label(env: Environment) -> None:
    html = _macros(env, "tstate('in_progress')")
    assert "tstate--in-progress" in html
    assert ">in progress<" in html
    assert "tstate__dot" in html


def test_origin_badge(env: Environment) -> None:
    html = _macros(env, "origin_badge('agent')")
    assert "origin-badge origin-badge--agent" in html
    assert ">agent<" in html


def test_derived_tag_names_the_inferring_surface(env: Environment) -> None:
    html = _macros(env, "derived_tag('mgf-fed-web')")
    assert "derived-tag" in html
    assert 'title="inferred by mgf-fed-web' in html


def test_absence_maps_state_to_kind(env: Environment) -> None:
    unknown = _macros(env, "absence('UNKNOWN', 'Not wired', 'No fed-resources/ found.')")
    assert "empty--unknown" in unknown
    assert "status-chip--unknown" in unknown
    assert ">?</div>" in unknown
    unreadable = _macros(
        env, "absence('UNREADABLE', 'Cannot read', 'Bad schema.', errors=['e1', 'e2'])"
    )
    assert "empty--unreadable" in unreadable
    assert ">!</div>" in unreadable
    assert "<li>e1</li>" in unreadable
    error = _macros(env, "absence('ERROR', 'Broken', 'Reason.', action='Fix it.')")
    assert "empty--no-data" in error
    assert "Fix it." in error


def test_empty_state(env: Environment) -> None:
    html = _macros(env, "empty_state('No past runs', 'Run something first.')")
    assert "empty--no-data" in html
    assert "∅" in html


# -------------------------------------------------------------- styleguide --


def test_styleguide_renders_the_whole_vocabulary(env: Environment) -> None:
    sprite = (static_dir() / "icons" / "icons-sprite.svg").read_text(encoding="utf-8")
    names = re.findall(r'<symbol id="mgf-icon-([a-z0-9-]+)"', sprite)
    html = env.get_template("mgf/styleguide.html").render(icon_names=names, kit_version="test")
    for marker in (
        'class="mgf-console"',  # it lives in the shell it documents
        "--mgf-text-4xl",  # the type ramp
        f"#mgf-icon-{names[0]}",  # the sprite, actually referenced
        "status-chip--in-sync",
        "tstate--in-progress",
        "origin-badge--ci",
        "derived-tag",
        "live-pane",
        "empty--unreadable",
    ):
        assert marker in html, marker
    # every sprite icon appears once in the grid
    assert html.count('<figure class="sg-icon-cell">') == len(names)
