"""
Coverage tests for local_deep_research/domain_classifier/classifier.py

Tests focus on paths not exercised by existing tests:
- DOMAIN_CATEGORIES structure
- DomainClassifier.__init__ stores attributes correctly
- _get_llm() lazy-initialises and caches the LLM
- _build_classification_prompt() with and without samples
- _get_domain_samples() SQL query is built correctly (mocked session)
- classify_domain() returns None on exception
- get_classification() returns None on exception
- get_all_classifications() returns [] on exception
- get_categories_summary() returns {} on exception
- classify_all_domains() with force_update=True skips existing check
"""

from unittest.mock import MagicMock, patch


# ---------------------------------------------------------------------------
# DOMAIN_CATEGORIES constant
# ---------------------------------------------------------------------------


class TestDomainCategories:
    def test_categories_dict_is_not_empty(self):
        from local_deep_research.domain_classifier.classifier import (
            DOMAIN_CATEGORIES,
        )

        assert isinstance(DOMAIN_CATEGORIES, dict)
        assert len(DOMAIN_CATEGORIES) > 0

    def test_other_category_present(self):
        from local_deep_research.domain_classifier.classifier import (
            DOMAIN_CATEGORIES,
        )

        assert "Other" in DOMAIN_CATEGORIES

    def test_all_values_are_lists(self):
        from local_deep_research.domain_classifier.classifier import (
            DOMAIN_CATEGORIES,
        )

        for cat, subcats in DOMAIN_CATEGORIES.items():
            assert isinstance(subcats, list), f"{cat} should have a list"


# ---------------------------------------------------------------------------
# DomainClassifier.__init__
# ---------------------------------------------------------------------------


class TestDomainClassifierInit:
    def test_stores_username_and_snapshot(self):
        from local_deep_research.domain_classifier.classifier import (
            DomainClassifier,
        )

        clf = DomainClassifier(username="alice", settings_snapshot={"k": "v"})
        assert clf.username == "alice"
        assert clf.settings_snapshot == {"k": "v"}
        assert clf.llm is None

    def test_defaults_snapshot_to_none(self):
        from local_deep_research.domain_classifier.classifier import (
            DomainClassifier,
        )

        clf = DomainClassifier(username="bob")
        assert clf.settings_snapshot is None


# ---------------------------------------------------------------------------
# _get_llm – lazy initialisation
# ---------------------------------------------------------------------------


class TestGetLlm:
    def test_llm_created_only_once(self):
        from local_deep_research.domain_classifier.classifier import (
            DomainClassifier,
        )

        clf = DomainClassifier(username="u")
        mock_llm = MagicMock()

        with patch(
            "local_deep_research.domain_classifier.classifier.get_llm",
            return_value=mock_llm,
        ) as mock_get:
            r1 = clf._get_llm()
            r2 = clf._get_llm()

        assert r1 is mock_llm
        assert r2 is mock_llm
        mock_get.assert_called_once()


# ---------------------------------------------------------------------------
# _build_classification_prompt
# ---------------------------------------------------------------------------


class TestBuildClassificationPrompt:
    def _make_clf(self):
        from local_deep_research.domain_classifier.classifier import (
            DomainClassifier,
        )

        return DomainClassifier(username="u")

    def test_prompt_contains_domain(self):
        clf = self._make_clf()
        prompt = clf._build_classification_prompt("example.com", [])
        assert "example.com" in prompt

    def test_prompt_contains_json_instruction(self):
        clf = self._make_clf()
        prompt = clf._build_classification_prompt("example.com", [])
        assert "JSON" in prompt

    def test_prompt_includes_sample_titles(self):
        clf = self._make_clf()
        samples = [{"title": "Hello World", "preview": "short preview"}]
        prompt = clf._build_classification_prompt("blog.io", samples)
        assert "Hello World" in prompt

    def test_prompt_without_samples_uses_fallback_text(self):
        clf = self._make_clf()
        prompt = clf._build_classification_prompt("unknown.io", [])
        assert "No samples available" in prompt


# ---------------------------------------------------------------------------
# classify_domain – exception returns None
# ---------------------------------------------------------------------------


class TestClassifyDomainException:
    def test_db_exception_returns_none(self):
        from local_deep_research.domain_classifier.classifier import (
            DomainClassifier,
        )

        clf = DomainClassifier(username="u")
        with patch(
            "local_deep_research.domain_classifier.classifier.get_user_db_session",
            side_effect=Exception("db fail"),
        ):
            result = clf.classify_domain("example.com")
        assert result is None


# ---------------------------------------------------------------------------
# get_classification – exception returns None
# ---------------------------------------------------------------------------


class TestGetClassificationException:
    def test_db_exception_returns_none(self):
        from local_deep_research.domain_classifier.classifier import (
            DomainClassifier,
        )

        clf = DomainClassifier(username="u")
        with patch(
            "local_deep_research.domain_classifier.classifier.get_user_db_session",
            side_effect=Exception("db fail"),
        ):
            result = clf.get_classification("example.com")
        assert result is None


# ---------------------------------------------------------------------------
# get_all_classifications – exception returns []
# ---------------------------------------------------------------------------


class TestGetAllClassificationsException:
    def test_db_exception_returns_empty_list(self):
        from local_deep_research.domain_classifier.classifier import (
            DomainClassifier,
        )

        clf = DomainClassifier(username="u")
        with patch(
            "local_deep_research.domain_classifier.classifier.get_user_db_session",
            side_effect=Exception("db fail"),
        ):
            result = clf.get_all_classifications()
        assert result == []


# ---------------------------------------------------------------------------
# get_categories_summary – exception returns {}
# ---------------------------------------------------------------------------


class TestGetCategoriesSummaryException:
    def test_db_exception_returns_empty_dict(self):
        from local_deep_research.domain_classifier.classifier import (
            DomainClassifier,
        )

        clf = DomainClassifier(username="u")
        with patch(
            "local_deep_research.domain_classifier.classifier.get_user_db_session",
            side_effect=Exception("db fail"),
        ):
            result = clf.get_categories_summary()
        assert result == {}


# ---------------------------------------------------------------------------
# classify_all_domains – outer exception
# ---------------------------------------------------------------------------


class TestClassifyAllDomainsException:
    def test_outer_exception_returns_error_dict(self):
        from local_deep_research.domain_classifier.classifier import (
            DomainClassifier,
        )

        clf = DomainClassifier(username="u")
        with patch(
            "local_deep_research.domain_classifier.classifier.get_user_db_session",
            side_effect=Exception("db fail"),
        ):
            result = clf.classify_all_domains()
        assert isinstance(result, dict)
        assert (
            "error" in result
            or "failed" in result
            or result.get("total", -1) >= 0
        )
