"""High-value pure logic tests for DomainClassifier and DOMAIN_CATEGORIES."""

import pytest

from local_deep_research.domain_classifier.classifier import (
    DOMAIN_CATEGORIES,
    DomainClassifier,
)


# ---------------------------------------------------------------------------
# DOMAIN_CATEGORIES dict tests
# ---------------------------------------------------------------------------


class TestDomainCategories:
    """Tests for the DOMAIN_CATEGORIES constant."""

    EXPECTED_MAIN_CATEGORIES = [
        "Academic & Research",
        "News & Media",
        "Reference & Documentation",
        "Social & Community",
        "Business & Commerce",
        "Technology",
        "Government & Organization",
        "Entertainment & Lifestyle",
        "Professional & Industry",
        "Other",
    ]

    def test_has_exactly_10_main_categories(self):
        assert len(DOMAIN_CATEGORIES) == 10

    @pytest.mark.parametrize("category", EXPECTED_MAIN_CATEGORIES)
    def test_main_category_exists(self, category):
        assert category in DOMAIN_CATEGORIES

    def test_every_category_has_subcategories(self):
        for cat, subcats in DOMAIN_CATEGORIES.items():
            assert isinstance(subcats, list), (
                f"{cat} subcategories should be a list"
            )
            assert len(subcats) > 0, (
                f"{cat} should have at least one subcategory"
            )

    def test_tech_news_in_news_and_media(self):
        assert "Tech News" in DOMAIN_CATEGORIES["News & Media"]

    def test_other_has_unknown_subcategory(self):
        assert "Unknown" in DOMAIN_CATEGORIES["Other"]

    def test_other_has_personal_website(self):
        assert "Personal Website" in DOMAIN_CATEGORIES["Other"]

    def test_academic_has_scientific_journal(self):
        assert "Scientific Journal" in DOMAIN_CATEGORIES["Academic & Research"]

    def test_technology_has_open_source_project(self):
        assert "Open Source Project" in DOMAIN_CATEGORIES["Technology"]

    def test_all_subcategories_are_strings(self):
        for cat, subcats in DOMAIN_CATEGORIES.items():
            for sub in subcats:
                assert isinstance(sub, str), (
                    f"Subcategory in {cat} must be a string"
                )


# ---------------------------------------------------------------------------
# Helper to build a DomainClassifier without touching DB/LLM
# ---------------------------------------------------------------------------


def _make_classifier():
    """Create a DomainClassifier instance (no real DB or LLM needed)."""
    return DomainClassifier(username="test_user", settings_snapshot={})


# ---------------------------------------------------------------------------
# _build_classification_prompt tests
# ---------------------------------------------------------------------------


class TestBuildClassificationPrompt:
    """Tests for _build_classification_prompt pure-logic method."""

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

    def test_prompt_contains_all_main_categories(self):
        clf = _make_classifier()
        prompt = clf._build_classification_prompt("example.com", [])
        for category in DOMAIN_CATEGORIES:
            assert category in prompt

    def test_prompt_says_no_samples_when_empty(self):
        clf = _make_classifier()
        prompt = clf._build_classification_prompt("example.com", [])
        assert "No samples available" in prompt

    def test_prompt_includes_sample_title(self):
        clf = _make_classifier()
        samples = [
            {"title": "My Great Article", "preview": "Some preview text"}
        ]
        prompt = clf._build_classification_prompt("example.com", samples)
        assert "My Great Article" in prompt

    def test_prompt_includes_sample_preview(self):
        clf = _make_classifier()
        samples = [{"title": "Title", "preview": "A short preview of content"}]
        prompt = clf._build_classification_prompt("example.com", samples)
        assert "A short preview of content" in prompt

    def test_prompt_omits_preview_when_none(self):
        clf = _make_classifier()
        samples = [{"title": "Title Only"}]
        prompt = clf._build_classification_prompt("example.com", samples)
        assert "Title Only" in prompt
        assert "Preview:" not in prompt

    def test_prompt_omits_preview_when_empty_string(self):
        clf = _make_classifier()
        samples = [{"title": "Title", "preview": ""}]
        prompt = clf._build_classification_prompt("example.com", samples)
        # Empty string is falsy, so no preview line
        assert "Preview:" not in prompt

    def test_only_first_5_samples_used(self):
        clf = _make_classifier()
        samples = [
            {"title": f"Sample {idx}", "preview": f"Preview {idx}"}
            for idx in range(8)
        ]
        prompt = clf._build_classification_prompt("example.com", samples)
        # Samples 0-4 should appear, samples 5-7 should not
        assert "Sample 4" in prompt
        assert "Sample 5" not in prompt

    def test_preview_truncated_to_100_chars(self):
        clf = _make_classifier()
        long_preview = "A" * 200
        samples = [{"title": "Title", "preview": long_preview}]
        prompt = clf._build_classification_prompt("example.com", samples)
        # The prompt should contain exactly 100 'A' characters followed by "..."
        assert "A" * 100 + "..." in prompt
        assert "A" * 101 not in prompt

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

    def test_prompt_mentions_confidence(self):
        clf = _make_classifier()
        prompt = clf._build_classification_prompt("example.com", [])
        assert "confidence" in prompt

    def test_prompt_with_multiple_samples_numbered(self):
        clf = _make_classifier()
        samples = [
            {"title": "First", "preview": "p1"},
            {"title": "Second", "preview": "p2"},
            {"title": "Third", "preview": "p3"},
        ]
        prompt = clf._build_classification_prompt("example.com", samples)
        assert "1. Title: First" in prompt
        assert "2. Title: Second" in prompt
        assert "3. Title: Third" in prompt

    def test_prompt_with_missing_preview_key(self):
        """Sample dict without 'preview' key at all should still work."""
        clf = _make_classifier()
        samples = [{"title": "No Preview Key"}]
        prompt = clf._build_classification_prompt("example.com", samples)
        assert "No Preview Key" in prompt
        assert "Preview:" not in prompt

    def test_prompt_subcategories_listed(self):
        """Subcategories should appear in the prompt's category listing."""
        clf = _make_classifier()
        prompt = clf._build_classification_prompt("example.com", [])
        assert "Q&A Platform" in prompt
        assert "Developer Tools" in prompt

    def test_prompt_does_not_say_no_samples_when_samples_present(self):
        clf = _make_classifier()
        samples = [{"title": "Exists", "preview": "content"}]
        prompt = clf._build_classification_prompt("example.com", samples)
        assert "No samples available" not in prompt


class TestDomainClassifierInit:
    """Tests for DomainClassifier initialisation (no side effects)."""

    def test_stores_username(self):
        clf = DomainClassifier(username="alice")
        assert clf.username == "alice"

    def test_stores_settings_snapshot(self):
        snap = {"model": "gpt-4"}
        clf = DomainClassifier(username="bob", settings_snapshot=snap)
        assert clf.settings_snapshot is snap

    def test_llm_starts_as_none(self):
        clf = DomainClassifier(username="charlie")
        assert clf.llm is None

    def test_default_settings_snapshot_is_none(self):
        clf = DomainClassifier(username="dave")
        assert clf.settings_snapshot is None
