"""
Deep behavioral tests for search_subscription.py pure logic.
Tests query transformation, evolution, statistics calculation,
and factory methods.
"""


# --- Query transformation detection ---


class TestQueryTransformationDetection:
    """Tests for detecting if query needs transformation."""

    def _needs_transform(self, query):
        query_lower = query.lower()
        return not any(
            term in query_lower
            for term in ["news", "latest", "recent", "today"]
        )

    def test_query_without_news_terms(self):
        assert self._needs_transform("AI research") is True

    def test_query_with_news(self):
        assert self._needs_transform("AI news") is False

    def test_query_with_latest(self):
        assert self._needs_transform("latest developments") is False

    def test_query_with_recent(self):
        assert self._needs_transform("recent updates") is False

    def test_query_with_today(self):
        assert self._needs_transform("events today") is False

    def test_case_insensitive(self):
        assert self._needs_transform("AI NEWS") is False
        assert self._needs_transform("LATEST TRENDS") is False


# --- Query type detection ---


class TestQueryTypeDetection:
    """Tests for detecting query type for transformation."""

    def _is_technical_query(self, query):
        query_lower = query.lower()
        return any(
            term in query_lower for term in ["how to", "tutorial", "guide"]
        )

    def _is_security_query(self, query):
        query_lower = query.lower()
        return any(
            term in query_lower
            for term in ["vulnerability", "security", "breach"]
        )

    def test_technical_how_to(self):
        assert self._is_technical_query("how to install python") is True

    def test_technical_tutorial(self):
        assert self._is_technical_query("python tutorial") is True

    def test_technical_guide(self):
        assert self._is_technical_query("deployment guide") is True

    def test_not_technical(self):
        assert self._is_technical_query("AI research") is False

    def test_security_vulnerability(self):
        assert self._is_security_query("log4j vulnerability") is True

    def test_security_breach(self):
        assert self._is_security_query("data breach 2025") is True

    def test_security_security(self):
        assert self._is_security_query("cybersecurity trends") is True

    def test_not_security(self):
        assert self._is_security_query("python programming") is False


# --- Query transformation ---


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

    def _transform_to_news_query(self, query):
        query_lower = query.lower()

        # Don't double-add news terms
        if any(
            term in query_lower
            for term in ["news", "latest", "recent", "today"]
        ):
            return query

        # Technical queries
        if any(term in query_lower for term in ["how to", "tutorial", "guide"]):
            return f"{query} latest updates developments"

        # Security queries
        if any(
            term in query_lower
            for term in ["vulnerability", "security", "breach"]
        ):
            return f"{query} breaking news alerts today"

        # General queries
        return f"{query} latest news developments"

    def test_already_has_news(self):
        result = self._transform_to_news_query("AI news")
        assert result == "AI news"

    def test_technical_query(self):
        result = self._transform_to_news_query("how to deploy docker")
        assert "latest updates developments" in result

    def test_security_query(self):
        result = self._transform_to_news_query("log4j vulnerability")
        assert "breaking news alerts today" in result

    def test_general_query(self):
        result = self._transform_to_news_query("machine learning")
        assert "latest news developments" in result

    def test_preserves_original(self):
        result = self._transform_to_news_query("AI research")
        assert "AI research" in result


# --- Date placeholder replacement ---


class TestDatePlaceholderReplacement:
    """Tests for YYYY-MM-DD placeholder replacement."""

    def _replace_date_placeholder(self, query, current_date):
        return query.replace("YYYY-MM-DD", current_date)

    def test_replaces_placeholder(self):
        query = "news from YYYY-MM-DD"
        result = self._replace_date_placeholder(query, "2025-06-15")
        assert result == "news from 2025-06-15"

    def test_no_placeholder(self):
        query = "AI news today"
        result = self._replace_date_placeholder(query, "2025-06-15")
        assert result == "AI news today"

    def test_multiple_placeholders(self):
        query = "events YYYY-MM-DD to YYYY-MM-DD"
        result = self._replace_date_placeholder(query, "2025-06-15")
        assert result == "events 2025-06-15 to 2025-06-15"


# --- Query evolution ---


class TestQueryEvolution:
    """Tests for evolve_query logic."""

    def _evolve_query(
        self, original_query, current_query, query_history, new_terms
    ):
        if new_terms:
            evolved_query = f"{original_query} {new_terms}"
            query_history.append(evolved_query)
            return evolved_query
        return current_query

    def test_adds_new_terms(self):
        history = ["AI news"]
        result = self._evolve_query("AI news", "AI news", history, "GPT-4")
        assert result == "AI news GPT-4"

    def test_appends_to_history(self):
        history = ["AI news"]
        self._evolve_query("AI news", "AI news", history, "GPT-4")
        assert len(history) == 2
        assert "AI news GPT-4" in history

    def test_no_change_without_terms(self):
        history = ["AI news"]
        result = self._evolve_query("AI news", "AI news", history, None)
        assert result == "AI news"

    def test_empty_terms_no_change(self):
        history = ["AI news"]
        result = self._evolve_query("AI news", "AI news", history, "")
        assert result == "AI news"


# --- Statistics calculation ---


class TestStatisticsCalculation:
    """Tests for get_statistics logic."""

    def _calc_success_rate(self, refresh_count, error_count):
        total = refresh_count + error_count
        if total > 0:
            return refresh_count / total
        return 0

    def test_all_success(self):
        rate = self._calc_success_rate(10, 0)
        assert rate == 1.0

    def test_half_success(self):
        rate = self._calc_success_rate(5, 5)
        assert rate == 0.5

    def test_no_refreshes(self):
        rate = self._calc_success_rate(0, 0)
        assert rate == 0

    def test_all_errors(self):
        rate = self._calc_success_rate(0, 10)
        assert rate == 0.0


class TestQueryEvolutionCount:
    """Tests for query evolution count."""

    def _evolution_count(self, query_history):
        return len(query_history) - 1

    def test_no_evolution(self):
        history = ["original"]
        assert self._evolution_count(history) == 0

    def test_one_evolution(self):
        history = ["original", "evolved"]
        assert self._evolution_count(history) == 1

    def test_multiple_evolutions(self):
        history = ["v1", "v2", "v3", "v4"]
        assert self._evolution_count(history) == 3


class TestStatisticsStructure:
    """Tests for statistics dictionary structure."""

    def _get_statistics(
        self,
        original_query,
        current_query,
        query_history,
        refresh_count,
        error_count,
    ):
        return {
            "original_query": original_query,
            "current_query": current_query,
            "query_evolution_count": len(query_history) - 1,
            "total_refreshes": refresh_count,
            "success_rate": (
                refresh_count / (refresh_count + error_count)
                if (refresh_count + error_count) > 0
                else 0
            ),
        }

    def test_has_original_query(self):
        stats = self._get_statistics("AI", "AI news", ["AI", "AI news"], 5, 1)
        assert stats["original_query"] == "AI"

    def test_has_current_query(self):
        stats = self._get_statistics("AI", "AI news", ["AI", "AI news"], 5, 1)
        assert stats["current_query"] == "AI news"

    def test_has_evolution_count(self):
        stats = self._get_statistics("AI", "AI news", ["AI", "AI news"], 5, 1)
        assert stats["query_evolution_count"] == 1


# --- To dict conversion ---


class TestToDictConversion:
    """Tests for to_dict data structure."""

    def _build_search_subscription_dict(
        self,
        base_dict,
        original_query,
        current_query,
        transform_enabled,
        query_history,
        statistics,
    ):
        data = base_dict.copy()
        data.update(
            {
                "original_query": original_query,
                "current_query": current_query,
                "transform_to_news_query": transform_enabled,
                "query_history": query_history,
                "statistics": statistics,
            }
        )
        return data

    def test_includes_original_query(self):
        result = self._build_search_subscription_dict(
            {}, "AI", "AI news", True, ["AI"], {}
        )
        assert result["original_query"] == "AI"

    def test_includes_transform_flag(self):
        result = self._build_search_subscription_dict(
            {}, "AI", "AI news", True, ["AI"], {}
        )
        assert result["transform_to_news_query"] is True

    def test_includes_query_history(self):
        result = self._build_search_subscription_dict(
            {}, "AI", "AI news", True, ["AI", "AI news"], {}
        )
        assert len(result["query_history"]) == 2


# --- Metadata structure ---


class TestMetadataStructure:
    """Tests for metadata dictionary structure."""

    def _build_metadata(self, query, transform_enabled):
        return {
            "subscription_type": "search",
            "original_query": query,
            "transform_enabled": transform_enabled,
        }

    def test_has_subscription_type(self):
        metadata = self._build_metadata("AI", True)
        assert metadata["subscription_type"] == "search"

    def test_has_original_query(self):
        metadata = self._build_metadata("AI news", True)
        assert metadata["original_query"] == "AI news"

    def test_has_transform_enabled(self):
        metadata = self._build_metadata("AI", False)
        assert metadata["transform_enabled"] is False


# --- Source creation ---


class TestSourceCreation:
    """Tests for CardSource creation in SearchSubscription."""

    def _create_default_source(self, query):
        return {
            "type": "user_search",
            "source_id": None,
            "created_from": f"Search subscription: {query}",
            "metadata": {},
        }

    def test_source_type(self):
        source = self._create_default_source("AI")
        assert source["type"] == "user_search"

    def test_created_from_includes_query(self):
        source = self._create_default_source("machine learning")
        assert "machine learning" in source["created_from"]


# --- Factory: from_user_search ---


class TestFactoryFromUserSearch:
    """Tests for SearchSubscriptionFactory.from_user_search."""

    def _build_source_from_search(
        self,
        search_query,
        search_result_id,
        search_timestamp=None,
        search_strategy=None,
    ):
        return {
            "type": "user_search",
            "source_id": search_result_id,
            "created_from": f"Your search: '{search_query}'",
            "metadata": {
                "search_timestamp": search_timestamp,
                "search_strategy": search_strategy,
            },
        }

    def test_source_type_user_search(self):
        source = self._build_source_from_search("AI", "s123")
        assert source["type"] == "user_search"

    def test_created_from_format(self):
        source = self._build_source_from_search("machine learning", "s123")
        assert source["created_from"] == "Your search: 'machine learning'"

    def test_includes_search_result_id(self):
        source = self._build_source_from_search("AI", "search-456")
        assert source["source_id"] == "search-456"

    def test_includes_metadata(self):
        source = self._build_source_from_search(
            "AI", "s1", search_timestamp="2025-06-15", search_strategy="quick"
        )
        assert source["metadata"]["search_timestamp"] == "2025-06-15"
        assert source["metadata"]["search_strategy"] == "quick"


# --- Factory: from_recommendation ---


class TestFactoryFromRecommendation:
    """Tests for SearchSubscriptionFactory.from_recommendation."""

    def _build_source_from_recommendation(
        self, recommendation_source, recommendation_type="topic_based"
    ):
        return {
            "type": "recommendation",
            "source_id": None,
            "created_from": f"Recommended based on: {recommendation_source}",
            "metadata": {"recommendation_type": recommendation_type},
        }

    def test_source_type_recommendation(self):
        source = self._build_source_from_recommendation("user interests")
        assert source["type"] == "recommendation"

    def test_created_from_format(self):
        source = self._build_source_from_recommendation("trending topics")
        assert source["created_from"] == "Recommended based on: trending topics"

    def test_default_recommendation_type(self):
        source = self._build_source_from_recommendation("interests")
        assert source["metadata"]["recommendation_type"] == "topic_based"

    def test_custom_recommendation_type(self):
        source = self._build_source_from_recommendation(
            "interests", recommendation_type="collaborative"
        )
        assert source["metadata"]["recommendation_type"] == "collaborative"


# --- Subscription type identifier ---


class TestSubscriptionTypeIdentifier:
    """Tests for get_subscription_type method."""

    def test_returns_search_subscription(self):
        subscription_type = "search_subscription"
        assert subscription_type == "search_subscription"

    def test_subscription_type_attribute(self):
        # The subscription_type attribute (not the method)
        attr_type = "search"
        assert attr_type == "search"


# --- Default refresh interval ---


class TestDefaultRefreshInterval:
    """Tests for default refresh interval."""

    def test_default_6_hours(self):
        default_interval = 360  # minutes
        assert default_interval == 360

    def test_in_minutes(self):
        interval = 360
        assert interval / 60 == 6  # 6 hours


# --- Query history management ---


class TestQueryHistoryManagement:
    """Tests for query history list management."""

    def test_initial_history(self):
        query = "AI news"
        history = [query]
        assert len(history) == 1
        assert history[0] == query

    def test_append_evolved_query(self):
        history = ["AI news"]
        history.append("AI news GPT-4")
        assert len(history) == 2
        assert history[-1] == "AI news GPT-4"

    def test_preserves_original(self):
        history = ["original"]
        history.append("evolved1")
        history.append("evolved2")
        assert history[0] == "original"


# --- Transform flag handling ---


class TestTransformFlagHandling:
    """Tests for transform_to_news_query flag."""

    def _generate_query(self, base_query, transform_enabled):
        if transform_enabled:
            return f"{base_query} latest news developments"
        return base_query

    def test_transform_enabled(self):
        result = self._generate_query("AI", True)
        assert "latest news developments" in result

    def test_transform_disabled(self):
        result = self._generate_query("AI", False)
        assert result == "AI"
