"""High-value tests for notifications/templates.py pure logic."""

import unittest
from unittest.mock import MagicMock, patch

from local_deep_research.notifications.templates import (
    EventType,
    NotificationTemplate,
)


class TestEventType(unittest.TestCase):
    def test_research_completed_value(self):
        assert EventType.RESEARCH_COMPLETED.value == "research_completed"

    def test_research_failed_value(self):
        assert EventType.RESEARCH_FAILED.value == "research_failed"

    def test_test_event_value(self):
        assert EventType.TEST.value == "test"

    def test_all_events_have_string_values(self):
        for event in EventType:
            assert isinstance(event.value, str)

    def test_event_categories_present(self):
        values = {e.value for e in EventType}
        assert "research_completed" in values
        assert "subscription_update" in values
        assert "rate_limit_warning" in values
        assert "test" in values


class TestFallbackTemplate(unittest.TestCase):
    def test_returns_dict_with_title_and_body(self):
        result = NotificationTemplate._get_fallback_template(
            EventType.RESEARCH_COMPLETED, {"query": "test"}
        )
        assert "title" in result
        assert "body" in result

    def test_title_contains_event_name(self):
        result = NotificationTemplate._get_fallback_template(
            EventType.RESEARCH_COMPLETED, {}
        )
        assert "Research Completed" in result["title"]

    def test_body_contains_context(self):
        result = NotificationTemplate._get_fallback_template(
            EventType.RESEARCH_FAILED, {"error": "timeout"}
        )
        assert "timeout" in result["body"]

    def test_underscores_replaced(self):
        result = NotificationTemplate._get_fallback_template(
            EventType.SUBSCRIPTION_UPDATE, {}
        )
        assert "_" not in result["title"]
        assert "Subscription Update" in result["title"]

    def test_different_event_types(self):
        for event_type in [
            EventType.RESEARCH_QUEUED,
            EventType.AUTH_ISSUE,
            EventType.TEST,
        ]:
            result = NotificationTemplate._get_fallback_template(event_type, {})
            assert "title" in result
            assert "body" in result


class TestFormatCustomTemplate(unittest.TestCase):
    def setUp(self):
        NotificationTemplate._jinja_env = None

    def test_custom_template_with_context(self):
        custom = {"title": "Hello {name}", "body": "Query: {query}"}
        result = NotificationTemplate.format(
            EventType.TEST,
            {"name": "user", "query": "test"},
            custom_template=custom,
        )
        assert result["title"] == "Hello user"
        assert result["body"] == "Query: test"

    def test_custom_template_missing_variable(self):
        custom = {"title": "Hello {name}", "body": "Query: {query}"}
        result = NotificationTemplate.format(
            EventType.TEST, {"name": "user"}, custom_template=custom
        )
        # Missing {query} triggers KeyError, both title and body get error fallback
        assert "Template error" in result["body"]
        assert "Missing variable" in result["body"]

    def test_custom_template_sanitizes_values(self):
        custom = {"title": "{val}", "body": "ok"}
        result = NotificationTemplate.format(
            EventType.TEST, {"val": 42}, custom_template=custom
        )
        assert result["title"] == "42"

    def test_custom_template_none_value_becomes_empty(self):
        custom = {"title": "{val}", "body": "ok"}
        result = NotificationTemplate.format(
            EventType.TEST, {"val": None}, custom_template=custom
        )
        assert result["title"] == ""


class TestFormatUnknownEvent(unittest.TestCase):
    def setUp(self):
        NotificationTemplate._jinja_env = None

    def test_unknown_event_not_in_template_files(self):
        # RATE_LIMIT_WARNING is not in TEMPLATE_FILES
        result = NotificationTemplate.format(
            EventType.RATE_LIMIT_WARNING, {"detail": "slow"}
        )
        assert "title" in result
        assert "body" in result


class TestFormatWithJinja(unittest.TestCase):
    def setUp(self):
        NotificationTemplate._jinja_env = None

    def test_jinja_env_not_available_uses_fallback(self):
        with patch.object(
            NotificationTemplate, "_get_jinja_env", return_value=None
        ):
            result = NotificationTemplate.format(
                EventType.RESEARCH_COMPLETED, {"query": "test"}
            )
            assert "title" in result
            assert "body" in result

    def test_jinja_template_render_error_uses_fallback(self):
        mock_env = MagicMock()
        mock_template = MagicMock()
        mock_template.render.side_effect = Exception("render error")
        mock_env.get_template.return_value = mock_template

        with patch.object(
            NotificationTemplate, "_get_jinja_env", return_value=mock_env
        ):
            result = NotificationTemplate.format(
                EventType.RESEARCH_COMPLETED, {"query": "test"}
            )
            assert "title" in result
            assert "body" in result
            # Verify the render path was actually exercised
            mock_template.render.assert_called_once()

    def test_jinja_successful_render(self):
        mock_env = MagicMock()
        mock_template = MagicMock()
        mock_template.render.return_value = (
            "My Title\nMy body content\nMore body"
        )
        mock_env.get_template.return_value = mock_template

        with patch.object(
            NotificationTemplate, "_get_jinja_env", return_value=mock_env
        ):
            result = NotificationTemplate.format(
                EventType.RESEARCH_COMPLETED, {"query": "test"}
            )
            assert result["title"] == "My Title"
            assert "My body content" in result["body"]


class TestGetRequiredContext(unittest.TestCase):
    def setUp(self):
        NotificationTemplate._jinja_env = None

    def test_unknown_event_returns_empty(self):
        result = NotificationTemplate.get_required_context(
            EventType.RATE_LIMIT_WARNING
        )
        assert result == []

    def test_no_jinja_env_returns_empty(self):
        with patch.object(
            NotificationTemplate, "_get_jinja_env", return_value=None
        ):
            result = NotificationTemplate.get_required_context(
                EventType.RESEARCH_COMPLETED
            )
            assert result == []

    def test_returns_sorted_list(self):
        mock_env = MagicMock()
        mock_loader = MagicMock()
        mock_loader.get_source.return_value = (
            "{{ query }} {{ status }}",
            None,
            None,
        )
        mock_env.loader = mock_loader
        mock_env.parse.return_value = MagicMock()

        mock_template = MagicMock()
        mock_template.environment = mock_env
        mock_env.get_template.return_value = mock_template

        import jinja2.meta  # noqa: F401 - ensure submodule is loaded

        with (
            patch.object(
                NotificationTemplate, "_get_jinja_env", return_value=mock_env
            ),
            patch.object(
                jinja2.meta,
                "find_undeclared_variables",
                return_value={"query", "status"},
            ),
        ):
            result = NotificationTemplate.get_required_context(
                EventType.RESEARCH_COMPLETED
            )
            assert result == ["query", "status"]


if __name__ == "__main__":
    unittest.main()
