"""Tests for the render() function and component loading in jinja_bridge.

These test functionality added in recent commits (render() API,
load_sx_dir, snake→kebab conversion) that isn't covered by the existing
shared/sx/tests/test_jinja_bridge.py.
"""
from __future__ import annotations

import os
import tempfile

import pytest

from shared.sx.jinja_bridge import (
    render,
    register_components,
    load_sx_dir,
    _COMPONENT_ENV,
)


@pytest.fixture(autouse=True)
def _clean_env():
    """Clear component env before each test."""
    _COMPONENT_ENV.clear()
    yield
    _COMPONENT_ENV.clear()


# ---------------------------------------------------------------------------
# render() — call component by name with Python kwargs
# ---------------------------------------------------------------------------

class TestRender:
    def test_basic_render(self):
        register_components('(defcomp ~shared:misc/badge (&key label) (span :class "badge" label))')
        html = render("badge", label="New")
        assert html == '<span class="badge">New</span>'

    def test_tilde_prefix_optional(self):
        register_components('(defcomp ~pill (&key text) (em text))')
        # Both forms should work
        assert render("pill", text="Hi") == render("~pill", text="Hi")

    def test_snake_to_kebab_conversion(self):
        """Python snake_case kwargs should map to sx kebab-case params."""
        register_components('''
            (defcomp ~card (&key nav-html link-href)
              (div :class "card" (a :href link-href nav-html)))
        ''')
        html = render("card", nav_html="Nav", link_href="/about")
        assert 'href="/about"' in html
        assert "Nav" in html

    def test_multiple_kwargs(self):
        register_components('''
            (defcomp ~item (&key title price image-url)
              (div (h3 title) (span price) (img :src image-url)))
        ''')
        html = render("item", title="Widget", price="£10", image_url="/img/w.jpg")
        assert "Widget" in html
        assert "£10" in html
        assert 'src="/img/w.jpg"' in html

    def test_unknown_component_raises(self):
        with pytest.raises(ValueError, match="Unknown component"):
            render("nonexistent", label="x")

    def test_empty_kwargs(self):
        register_components('(defcomp ~empty () (hr))')
        html = render("empty")
        assert html == "<hr>"

    def test_html_escaping_in_values(self):
        register_components('(defcomp ~safe (&key text) (p text))')
        html = render("safe", text='<script>alert("xss")</script>')
        assert "<script>" not in html
        assert "&lt;script&gt;" in html

    def test_boolean_false_value(self):
        register_components('''
            (defcomp ~toggle (&key active)
              (when active (span "ON")))
        ''')
        html = render("toggle", active=False)
        assert "ON" not in html

    def test_boolean_true_value(self):
        register_components('''
            (defcomp ~toggle (&key active)
              (when active (span "ON")))
        ''')
        html = render("toggle", active=True)
        assert "ON" in html


# ---------------------------------------------------------------------------
# load_sx_dir
# ---------------------------------------------------------------------------

class TestLoadSxDir:
    def test_loads_sx_files(self):
        with tempfile.TemporaryDirectory() as tmpdir:
            # Write a .sx file
            with open(os.path.join(tmpdir, "components.sx"), "w") as f:
                f.write('(defcomp ~test-comp (&key msg) (div msg))')

            load_sx_dir(tmpdir)
            html = render("test-comp", msg="loaded!")
            assert html == "<div>loaded!</div>"

    def test_loads_sx_files_alt(self):
        with tempfile.TemporaryDirectory() as tmpdir:
            with open(os.path.join(tmpdir, "nav.sx"), "w") as f:
                f.write('(defcomp ~nav-item (&key href label) (a :href href label))')

            load_sx_dir(tmpdir)
            html = render("nav-item", href="/about", label="About")
            assert 'href="/about"' in html

    def test_loads_multiple_files(self):
        with tempfile.TemporaryDirectory() as tmpdir:
            with open(os.path.join(tmpdir, "a.sx"), "w") as f:
                f.write('(defcomp ~comp-a (&key x) (b x))')
            with open(os.path.join(tmpdir, "b.sx"), "w") as f:
                f.write('(defcomp ~comp-b (&key y) (i y))')

            load_sx_dir(tmpdir)
            assert render("comp-a", x="A") == "<b>A</b>"
            assert render("comp-b", y="B") == "<i>B</i>"

    def test_empty_directory(self):
        with tempfile.TemporaryDirectory() as tmpdir:
            load_sx_dir(tmpdir)  # should not raise

    def test_ignores_non_sx_files(self):
        with tempfile.TemporaryDirectory() as tmpdir:
            with open(os.path.join(tmpdir, "readme.txt"), "w") as f:
                f.write("not a sx file")
            with open(os.path.join(tmpdir, "comp.sx"), "w") as f:
                f.write('(defcomp ~real (&key v) (span v))')

            load_sx_dir(tmpdir)
            assert "~real" in _COMPONENT_ENV
            # txt file should not have been loaded
            assert len([k for k in _COMPONENT_ENV if k.startswith("~")]) == 1


# ---------------------------------------------------------------------------
# register_components — multiple definitions in one source
# ---------------------------------------------------------------------------

class TestRegisterComponents:
    def test_multiple_in_one_source(self):
        register_components('''
            (defcomp ~a (&key x) (b x))
            (defcomp ~b (&key y) (i y))
        ''')
        assert "~a" in _COMPONENT_ENV
        assert "~b" in _COMPONENT_ENV

    def test_overwrite_existing(self):
        register_components('(defcomp ~ow (&key x) (b x))')
        assert render("ow", x="v1") == "<b>v1</b>"
        register_components('(defcomp ~ow (&key x) (i x))')
        assert render("ow", x="v2") == "<i>v2</i>"
