"""
Extended tests for news/subscription_manager/search_subscription.py

Tests cover:
- SearchSubscription initialization and defaults
- query property - backward compatibility
- generate_search_query() - query generation and transformation
- _transform_to_news_query() - news context addition
- evolve_query() - query evolution
- get_statistics() - statistics calculation
- to_dict() - serialization
- SearchSubscriptionFactory - factory methods
"""

import pytest
from unittest.mock import patch, MagicMock


@pytest.fixture(autouse=True)
def mock_storage():
    """Mock SQLSubscriptionStorage for all tests."""
    with patch(
        "local_deep_research.news.subscription_manager.base_subscription.SQLSubscriptionStorage"
    ) as mock:
        mock.return_value = MagicMock()
        yield mock


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

    def test_creates_with_required_args(self):
        """Creates subscription with just user_id and query."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(user_id="user123", query="python tutorials")

        assert sub.user_id == "user123"
        assert sub.original_query == "python tutorials"

    def test_default_refresh_interval_is_360_minutes(self):
        """Default refresh interval is 6 hours (360 minutes)."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(user_id="user1", query="test")

        assert sub.refresh_interval_minutes == 360

    def test_custom_refresh_interval(self):
        """Custom refresh interval is respected."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(
            user_id="user1", query="test", refresh_interval_minutes=120
        )

        assert sub.refresh_interval_minutes == 120

    def test_auto_creates_source_when_not_provided(self):
        """Auto-creates CardSource when not provided."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(user_id="user1", query="machine learning")

        assert sub.source is not None
        assert sub.source.type == "user_search"
        assert "machine learning" in sub.source.created_from

    def test_uses_provided_source(self):
        """Uses provided CardSource."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )
        from local_deep_research.news.core.base_card import CardSource

        custom_source = CardSource(type="custom", source_id="src-1")
        sub = SearchSubscription(
            user_id="user1", query="test", source=custom_source
        )

        assert sub.source.type == "custom"

    def test_transform_to_news_query_defaults_true(self):
        """transform_to_news_query defaults to True."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(user_id="user1", query="test")

        assert sub.transform_to_news_query is True

    def test_can_disable_transform(self):
        """Can disable query transformation."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(
            user_id="user1", query="test", transform_to_news_query=False
        )

        assert sub.transform_to_news_query is False

    def test_subscription_type_is_search(self):
        """Subscription type is set to 'search'."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(user_id="user1", query="test")

        assert sub.subscription_type == "search"

    def test_initializes_query_history(self):
        """Query history is initialized with original query."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(user_id="user1", query="original query")

        assert sub.query_history == ["original query"]
        assert sub.current_query == "original query"

    def test_metadata_includes_original_query(self):
        """Metadata includes original query."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(user_id="user1", query="test query")

        assert sub.metadata["original_query"] == "test query"
        assert sub.metadata["subscription_type"] == "search"
        assert sub.metadata["transform_enabled"] is True

    def test_get_subscription_type_returns_search_subscription(self):
        """get_subscription_type returns 'search_subscription'."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(user_id="user1", query="test")

        assert sub.get_subscription_type() == "search_subscription"


class TestQueryProperty:
    """Tests for SearchSubscription.query property."""

    def test_returns_original_query(self):
        """query property returns original_query."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(user_id="user1", query="my search query")

        assert sub.query == "my search query"

    def test_backward_compatibility(self):
        """query property provides backward compatibility."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(user_id="user1", query="test")
        sub.original_query = "modified"

        assert sub.query == "modified"


class TestGenerateSearchQuery:
    """Tests for SearchSubscription.generate_search_query()."""

    def test_returns_string(self):
        """Returns a string query."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(user_id="user1", query="test query")
        result = sub.generate_search_query()

        assert isinstance(result, str)

    def test_replaces_date_placeholder(self):
        """Replaces YYYY-MM-DD placeholder with current date."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(user_id="user1", query="events on YYYY-MM-DD")
        result = sub.generate_search_query()

        assert "YYYY-MM-DD" not in result

    def test_transforms_when_enabled(self):
        """Transforms query when transform_to_news_query is True."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(
            user_id="user1",
            query="python programming",
            transform_to_news_query=True,
        )
        result = sub.generate_search_query()

        # Should add news terms
        assert "news" in result.lower() or "developments" in result.lower()

    def test_no_transform_when_disabled(self):
        """Does not transform when transform_to_news_query is False."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(
            user_id="user1",
            query="exact query",
            transform_to_news_query=False,
        )
        result = sub.generate_search_query()

        assert result == "exact query"

    def test_uses_current_query(self):
        """Uses current_query, not original."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(
            user_id="user1", query="original", transform_to_news_query=False
        )
        sub.current_query = "evolved"

        result = sub.generate_search_query()

        assert "evolved" in result


class TestTransformToNewsQuery:
    """Tests for SearchSubscription._transform_to_news_query()."""

    def test_skips_if_already_has_news(self):
        """Does not add news terms if query already contains 'news'."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(user_id="user1", query="test")
        result = sub._transform_to_news_query("breaking news today")

        assert result == "breaking news today"

    def test_skips_if_already_has_latest(self):
        """Does not add terms if query already contains 'latest'."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(user_id="user1", query="test")
        result = sub._transform_to_news_query("latest python updates")

        assert result == "latest python updates"

    def test_skips_if_already_has_recent(self):
        """Does not add terms if query already contains 'recent'."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(user_id="user1", query="test")
        result = sub._transform_to_news_query("recent developments")

        assert result == "recent developments"

    def test_skips_if_already_has_today(self):
        """Does not add terms if query already contains 'today'."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(user_id="user1", query="test")
        result = sub._transform_to_news_query("events today")

        assert result == "events today"

    def test_adds_updates_for_how_to_queries(self):
        """Adds 'updates developments' for how-to queries."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(user_id="user1", query="test")
        result = sub._transform_to_news_query("how to use python")

        assert "updates" in result.lower()
        assert "developments" in result.lower()

    def test_adds_updates_for_tutorial_queries(self):
        """Adds 'updates developments' for tutorial queries."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(user_id="user1", query="test")
        result = sub._transform_to_news_query("python tutorial")

        assert "updates" in result.lower()

    def test_adds_breaking_for_security_queries(self):
        """Adds 'breaking news alerts' for security queries."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(user_id="user1", query="test")
        result = sub._transform_to_news_query("log4j vulnerability")

        assert "breaking" in result.lower()
        assert "alerts" in result.lower()

    def test_adds_breaking_for_breach_queries(self):
        """Adds 'breaking news alerts' for breach queries."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(user_id="user1", query="test")
        result = sub._transform_to_news_query("data breach company")

        assert "breaking" in result.lower()

    def test_adds_news_for_general_queries(self):
        """Adds 'latest news developments' for general queries."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(user_id="user1", query="test")
        result = sub._transform_to_news_query("python programming")

        assert "news" in result.lower()
        assert "developments" in result.lower()

    def test_preserves_original_query(self):
        """Preserves the original query in the result."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(user_id="user1", query="test")
        result = sub._transform_to_news_query("my specific query")

        assert "my specific query" in result


class TestEvolveQuery:
    """Tests for SearchSubscription.evolve_query()."""

    def test_updates_current_query(self):
        """Updates current_query with new terms."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(user_id="user1", query="python")

        sub.evolve_query("3.12")

        assert sub.current_query == "python 3.12"

    def test_adds_to_query_history(self):
        """Adds evolved query to history."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(user_id="user1", query="python")

        sub.evolve_query("tutorials")

        assert len(sub.query_history) == 2
        assert "python tutorials" in sub.query_history

    def test_no_change_with_none(self):
        """No change when new_terms is None."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(user_id="user1", query="original")

        sub.evolve_query(None)

        assert sub.current_query == "original"
        assert len(sub.query_history) == 1

    def test_no_change_with_empty_string(self):
        """No change when new_terms is empty string."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(user_id="user1", query="original")

        sub.evolve_query("")

        # Empty string is falsy, so no change
        assert sub.current_query == "original"

    def test_multiple_evolutions(self):
        """Tracks multiple evolutions."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(user_id="user1", query="AI")

        sub.evolve_query("GPT")
        sub.evolve_query("Claude")

        assert len(sub.query_history) == 3


class TestGetStatistics:
    """Tests for SearchSubscription.get_statistics()."""

    def test_includes_original_query(self):
        """Statistics include original query."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(user_id="user1", query="original search")
        stats = sub.get_statistics()

        assert stats["original_query"] == "original search"

    def test_includes_current_query(self):
        """Statistics include current query."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(user_id="user1", query="original")
        sub.current_query = "evolved"
        stats = sub.get_statistics()

        assert stats["current_query"] == "evolved"

    def test_counts_evolutions(self):
        """Counts query evolutions."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(user_id="user1", query="base")
        sub.evolve_query("new1")
        sub.evolve_query("new2")

        stats = sub.get_statistics()

        assert stats["query_evolution_count"] == 2

    def test_includes_total_refreshes(self):
        """Includes total refresh count."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(user_id="user1", query="test")
        sub.refresh_count = 10

        stats = sub.get_statistics()

        assert stats["total_refreshes"] == 10

    def test_calculates_success_rate(self):
        """Calculates success rate correctly."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(user_id="user1", query="test")
        sub.refresh_count = 8
        sub.error_count = 2

        stats = sub.get_statistics()

        assert stats["success_rate"] == 0.8

    def test_success_rate_zero_with_no_attempts(self):
        """Success rate is 0 when no refreshes or errors."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(user_id="user1", query="test")
        sub.refresh_count = 0
        sub.error_count = 0

        stats = sub.get_statistics()

        assert stats["success_rate"] == 0

    def test_success_rate_handles_all_errors(self):
        """Success rate is 0 when all attempts are errors."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(user_id="user1", query="test")
        sub.refresh_count = 0
        sub.error_count = 5

        stats = sub.get_statistics()

        assert stats["success_rate"] == 0


class TestSearchSubscriptionToDict:
    """Tests for SearchSubscription.to_dict()."""

    def test_includes_original_query(self):
        """Dict includes original_query."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(user_id="user1", query="my query")
        data = sub.to_dict()

        assert data["original_query"] == "my query"

    def test_includes_current_query(self):
        """Dict includes current_query."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(user_id="user1", query="original")
        sub.current_query = "current"
        data = sub.to_dict()

        assert data["current_query"] == "current"

    def test_includes_transform_flag(self):
        """Dict includes transform_to_news_query flag."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(
            user_id="user1", query="test", transform_to_news_query=False
        )
        data = sub.to_dict()

        assert data["transform_to_news_query"] is False

    def test_includes_query_history(self):
        """Dict includes query_history."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(user_id="user1", query="v1")
        sub.evolve_query("v2")
        data = sub.to_dict()

        assert "v1" in data["query_history"]

    def test_includes_statistics(self):
        """Dict includes statistics."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscription,
        )

        sub = SearchSubscription(user_id="user1", query="test")
        data = sub.to_dict()

        assert "statistics" in data


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

    def test_from_user_search_creates_subscription(self):
        """from_user_search creates a valid subscription."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscriptionFactory,
        )

        sub = SearchSubscriptionFactory.from_user_search(
            user_id="user1",
            search_query="machine learning",
        )

        assert sub.original_query == "machine learning"
        assert sub.user_id == "user1"

    def test_from_user_search_sets_source_id(self):
        """from_user_search sets source_id when provided."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscriptionFactory,
        )

        sub = SearchSubscriptionFactory.from_user_search(
            user_id="user1",
            search_query="test",
            search_result_id="result-123",
        )

        assert sub.source.source_id == "result-123"

    def test_from_user_search_sets_source_type(self):
        """from_user_search sets source type to user_search."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscriptionFactory,
        )

        sub = SearchSubscriptionFactory.from_user_search(
            user_id="user1",
            search_query="test",
        )

        assert sub.source.type == "user_search"

    def test_from_user_search_has_metadata_keys(self):
        """from_user_search creates source with metadata keys for search_strategy."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscriptionFactory,
        )

        sub = SearchSubscriptionFactory.from_user_search(
            user_id="user1",
            search_query="test",
        )

        # Metadata keys are set (to None when not provided)
        assert "search_strategy" in sub.source.metadata
        assert "search_timestamp" in sub.source.metadata

    def test_from_recommendation_creates_subscription(self):
        """from_recommendation creates a valid subscription."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscriptionFactory,
        )

        sub = SearchSubscriptionFactory.from_recommendation(
            user_id="user1",
            recommended_query="trending topic",
            recommendation_source="topic_analyzer",
        )

        assert sub.original_query == "trending topic"
        assert sub.source.type == "recommendation"

    def test_from_recommendation_records_source(self):
        """from_recommendation records recommendation source."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscriptionFactory,
        )

        sub = SearchSubscriptionFactory.from_recommendation(
            user_id="user1",
            recommended_query="test",
            recommendation_source="interest_analyzer",
        )

        assert "interest_analyzer" in sub.source.created_from

    def test_from_recommendation_includes_default_type_metadata(self):
        """from_recommendation includes default recommendation_type in metadata."""
        from local_deep_research.news.subscription_manager.search_subscription import (
            SearchSubscriptionFactory,
        )

        sub = SearchSubscriptionFactory.from_recommendation(
            user_id="user1",
            recommended_query="test",
            recommendation_source="test",
        )

        # Default recommendation_type is "topic_based"
        assert sub.source.metadata["recommendation_type"] == "topic_based"
