"""
Deep behavioral tests for SearchSubscription.
Tests query transformation, evolution, statistics, and factory methods.
"""

from unittest.mock import patch


from local_deep_research.news.core.base_card import CardSource


def _make_search_sub(query="AI research", user_id="user1", **kwargs):
    """Create a SearchSubscription with mocked storage."""
    from local_deep_research.news.subscription_manager.search_subscription import (
        SearchSubscription,
    )

    with patch(
        "local_deep_research.news.subscription_manager.base_subscription.SQLSubscriptionStorage"
    ):
        return SearchSubscription(query=query, user_id=user_id, **kwargs)


# --- Init ---


class TestSearchSubscriptionInit:
    """Tests for SearchSubscription initialization."""

    def test_query_stored(self):
        sub = _make_search_sub(query="python tutorials")
        assert sub.original_query == "python tutorials"

    def test_current_query_equals_original(self):
        sub = _make_search_sub(query="python")
        assert sub.current_query == "python"

    def test_query_property_returns_original(self):
        sub = _make_search_sub(query="test")
        assert sub.query == "test"

    def test_query_history_initialized(self):
        sub = _make_search_sub(query="test")
        assert sub.query_history == ["test"]

    def test_transform_enabled_by_default(self):
        sub = _make_search_sub()
        assert sub.transform_to_news_query is True

    def test_transform_can_be_disabled(self):
        sub = _make_search_sub(transform_to_news_query=False)
        assert sub.transform_to_news_query is False

    def test_subscription_type_is_search(self):
        sub = _make_search_sub()
        assert sub.subscription_type == "search"

    def test_metadata_includes_subscription_type(self):
        sub = _make_search_sub()
        assert sub.metadata["subscription_type"] == "search"

    def test_metadata_includes_original_query(self):
        sub = _make_search_sub(query="quantum")
        assert sub.metadata["original_query"] == "quantum"

    def test_metadata_includes_transform_enabled(self):
        sub = _make_search_sub(transform_to_news_query=False)
        assert sub.metadata["transform_enabled"] is False

    def test_default_interval_360(self):
        sub = _make_search_sub()
        assert sub.refresh_interval_minutes == 360

    def test_auto_creates_source_if_none(self):
        sub = _make_search_sub()
        assert sub.source.type == "user_search"

    def test_uses_provided_source(self):
        source = CardSource(type="custom")
        sub = _make_search_sub(source=source)
        assert sub.source.type == "custom"

    def test_get_subscription_type(self):
        sub = _make_search_sub()
        assert sub.get_subscription_type() == "search_subscription"


# --- Query transformation ---


class TestTransformToNewsQuery:
    """Tests for _transform_to_news_query logic."""

    def test_adds_news_terms_to_general_query(self):
        sub = _make_search_sub(query="artificial intelligence")
        result = sub._transform_to_news_query("artificial intelligence")
        assert "news" in result.lower() or "developments" in result.lower()

    def test_skips_transform_if_news_already_present(self):
        sub = _make_search_sub()
        result = sub._transform_to_news_query("AI news analysis")
        assert result == "AI news analysis"

    def test_skips_transform_if_latest_present(self):
        sub = _make_search_sub()
        result = sub._transform_to_news_query("latest AI research")
        assert result == "latest AI research"

    def test_skips_transform_if_recent_present(self):
        sub = _make_search_sub()
        result = sub._transform_to_news_query("recent developments in ML")
        assert result == "recent developments in ML"

    def test_skips_transform_if_today_present(self):
        sub = _make_search_sub()
        result = sub._transform_to_news_query("events today")
        assert result == "events today"

    def test_how_to_query_gets_updates_terms(self):
        sub = _make_search_sub()
        result = sub._transform_to_news_query("how to use docker")
        assert "updates" in result.lower() or "developments" in result.lower()

    def test_tutorial_query_gets_updates_terms(self):
        sub = _make_search_sub()
        result = sub._transform_to_news_query("python tutorial")
        assert "updates" in result.lower() or "developments" in result.lower()

    def test_security_query_gets_breaking_terms(self):
        sub = _make_search_sub()
        result = sub._transform_to_news_query("Log4j vulnerability")
        assert "breaking" in result.lower() or "alerts" in result.lower()

    def test_breach_query_gets_breaking_terms(self):
        sub = _make_search_sub()
        result = sub._transform_to_news_query("data breach company X")
        assert "breaking" in result.lower() or "alerts" in result.lower()

    def test_case_insensitive_detection(self):
        sub = _make_search_sub()
        # "NEWS" should still be detected
        result = sub._transform_to_news_query("AI NEWS today")
        assert result == "AI NEWS today"


# --- Generate search query ---


class TestGenerateSearchQuery:
    """Tests for generate_search_query."""

    def test_transforms_by_default(self):
        sub = _make_search_sub(query="quantum computing")
        query = sub.generate_search_query()
        assert "quantum computing" in query
        assert len(query) > len("quantum computing")

    def test_no_transform_when_disabled(self):
        sub = _make_search_sub(
            query="quantum computing", transform_to_news_query=False
        )
        query = sub.generate_search_query()
        assert query == "quantum computing"

    def test_uses_current_query_not_original(self):
        sub = _make_search_sub(query="AI")
        sub.current_query = "Artificial General Intelligence"
        query = sub.generate_search_query()
        assert "Artificial General Intelligence" in query


# --- Query evolution ---


class TestEvolveQuery:
    """Tests for evolve_query."""

    def test_evolves_with_new_terms(self):
        sub = _make_search_sub(query="AI research")
        sub.evolve_query("2024 trends")
        assert "2024 trends" in sub.current_query

    def test_includes_original_query(self):
        sub = _make_search_sub(query="AI research")
        sub.evolve_query("trends")
        assert "AI research" in sub.current_query

    def test_adds_to_history(self):
        sub = _make_search_sub(query="AI")
        sub.evolve_query("ML advances")
        assert len(sub.query_history) == 2

    def test_no_change_with_none(self):
        sub = _make_search_sub(query="AI")
        sub.evolve_query(None)
        assert sub.current_query == "AI"
        assert len(sub.query_history) == 1

    def test_no_change_with_empty_string(self):
        sub = _make_search_sub(query="AI")
        sub.evolve_query("")
        assert sub.current_query == "AI"


# --- Statistics ---


class TestSearchSubscriptionStatistics:
    """Tests for get_statistics."""

    def test_includes_original_query(self):
        sub = _make_search_sub(query="AI research")
        stats = sub.get_statistics()
        assert stats["original_query"] == "AI research"

    def test_includes_current_query(self):
        sub = _make_search_sub(query="AI")
        sub.current_query = "AI ML"
        stats = sub.get_statistics()
        assert stats["current_query"] == "AI ML"

    def test_query_evolution_count(self):
        sub = _make_search_sub(query="AI")
        sub.evolve_query("new terms")
        stats = sub.get_statistics()
        assert stats["query_evolution_count"] == 1

    def test_total_refreshes(self):
        sub = _make_search_sub()
        sub.refresh_count = 10
        stats = sub.get_statistics()
        assert stats["total_refreshes"] == 10

    def test_success_rate_zero_when_no_activity(self):
        sub = _make_search_sub()
        stats = sub.get_statistics()
        assert stats["success_rate"] == 0

    def test_success_rate_calculation(self):
        sub = _make_search_sub()
        sub.refresh_count = 8
        sub.error_count = 2
        stats = sub.get_statistics()
        assert stats["success_rate"] == 0.8

    def test_success_rate_perfect(self):
        sub = _make_search_sub()
        sub.refresh_count = 10
        sub.error_count = 0
        stats = sub.get_statistics()
        assert stats["success_rate"] == 1.0


# --- to_dict ---


class TestSearchSubscriptionToDict:
    """Tests for to_dict serialization."""

    def test_includes_original_query(self):
        sub = _make_search_sub(query="AI")
        d = sub.to_dict()
        assert d["original_query"] == "AI"

    def test_includes_current_query(self):
        sub = _make_search_sub(query="AI")
        sub.current_query = "AI ML"
        d = sub.to_dict()
        assert d["current_query"] == "AI ML"

    def test_includes_transform_flag(self):
        sub = _make_search_sub(transform_to_news_query=False)
        d = sub.to_dict()
        assert d["transform_to_news_query"] is False

    def test_includes_query_history(self):
        sub = _make_search_sub(query="AI")
        sub.evolve_query("ML")
        d = sub.to_dict()
        assert len(d["query_history"]) == 2

    def test_includes_statistics(self):
        sub = _make_search_sub()
        d = sub.to_dict()
        assert "statistics" in d

    def test_includes_base_fields(self):
        sub = _make_search_sub()
        d = sub.to_dict()
        assert "id" in d
        assert "user_id" in d
        assert "type" in d


# --- Factory ---


class TestSearchSubscriptionFactory:
    """Tests for SearchSubscriptionFactory."""

    def test_from_user_search(self):
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscriptionFactory,
        )

        with patch(
            "local_deep_research.news.subscription_manager.base_subscription.SQLSubscriptionStorage"
        ):
            sub = SearchSubscriptionFactory.from_user_search(
                user_id="u1",
                search_query="python async patterns",
                search_result_id="res-42",
            )
        assert sub.original_query == "python async patterns"
        assert sub.source.type == "user_search"
        assert sub.source.source_id == "res-42"

    def test_from_recommendation(self):
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscriptionFactory,
        )

        with patch(
            "local_deep_research.news.subscription_manager.base_subscription.SQLSubscriptionStorage"
        ):
            sub = SearchSubscriptionFactory.from_recommendation(
                user_id="u1",
                recommended_query="emerging AI research",
                recommendation_source="user_preferences",
            )
        assert sub.original_query == "emerging AI research"
        assert sub.source.type == "recommendation"

    def test_factory_passes_kwargs(self):
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscriptionFactory,
        )

        with patch(
            "local_deep_research.news.subscription_manager.base_subscription.SQLSubscriptionStorage"
        ):
            sub = SearchSubscriptionFactory.from_user_search(
                user_id="u1",
                search_query="test",
                refresh_interval_minutes=120,
            )
        assert sub.refresh_interval_minutes == 120
