"""
Comprehensive tests for the WikiNews search engine.
Tests initialization, query optimization, date adaptation, and search execution.

Note: These tests mock HTTP requests to avoid requiring an API connection.
"""

import pytest
from unittest.mock import Mock
from datetime import datetime, timedelta, UTC


class TestWikinewsSearchEngineInit:
    """Tests for WikiNews search engine initialization."""

    def test_init_default_values(self):
        """Test initialization with default values."""
        from local_deep_research.web_search_engines.engines.search_engine_wikinews import (
            WikinewsSearchEngine,
        )

        engine = WikinewsSearchEngine()

        assert engine.max_results == 10
        assert engine.lang_code == "en"
        assert engine.adaptive_search is True
        assert engine.is_public is True
        assert engine.is_news is True

    def test_init_with_custom_max_results(self):
        """Test initialization with custom max results."""
        from local_deep_research.web_search_engines.engines.search_engine_wikinews import (
            WikinewsSearchEngine,
        )

        engine = WikinewsSearchEngine(max_results=25)
        assert engine.max_results == 25

    def test_init_with_english_language(self):
        """Test initialization with English language."""
        from local_deep_research.web_search_engines.engines.search_engine_wikinews import (
            WikinewsSearchEngine,
        )

        engine = WikinewsSearchEngine(search_language="english")
        assert engine.lang_code == "en"

    def test_init_with_german_language(self):
        """Test initialization with German language."""
        from local_deep_research.web_search_engines.engines.search_engine_wikinews import (
            WikinewsSearchEngine,
        )

        engine = WikinewsSearchEngine(search_language="german")
        assert engine.lang_code == "de"

    def test_init_with_french_language(self):
        """Test initialization with French language."""
        from local_deep_research.web_search_engines.engines.search_engine_wikinews import (
            WikinewsSearchEngine,
        )

        engine = WikinewsSearchEngine(search_language="french")
        assert engine.lang_code == "fr"

    def test_init_with_unsupported_language_defaults_to_english(self):
        """Test that unsupported languages default to English."""
        from local_deep_research.web_search_engines.engines.search_engine_wikinews import (
            WikinewsSearchEngine,
        )

        engine = WikinewsSearchEngine(search_language="klingon")
        assert engine.lang_code == "en"

    def test_init_with_adaptive_search_disabled(self):
        """Test initialization with adaptive search disabled."""
        from local_deep_research.web_search_engines.engines.search_engine_wikinews import (
            WikinewsSearchEngine,
        )

        engine = WikinewsSearchEngine(adaptive_search=False)
        assert engine.adaptive_search is False

    def test_init_with_snippets_only(self):
        """Test initialization with snippets only mode."""
        from local_deep_research.web_search_engines.engines.search_engine_wikinews import (
            WikinewsSearchEngine,
        )

        engine = WikinewsSearchEngine(search_snippets_only=True)
        assert engine.search_snippets_only is True


class TestWikinewsTimePeriod:
    """Tests for WikiNews time period configuration."""

    def test_time_period_year(self):
        """Test time period set to 1 year."""
        from local_deep_research.web_search_engines.engines.search_engine_wikinews import (
            WikinewsSearchEngine,
        )

        engine = WikinewsSearchEngine(time_period="y")

        now = datetime.now(UTC)
        expected_from = now - timedelta(days=365)

        # Allow some tolerance for test execution time
        assert abs((engine.from_date - expected_from).total_seconds()) < 5
        assert abs((engine.to_date - now).total_seconds()) < 5

    def test_time_period_month(self):
        """Test time period set to 1 month."""
        from local_deep_research.web_search_engines.engines.search_engine_wikinews import (
            WikinewsSearchEngine,
        )

        engine = WikinewsSearchEngine(time_period="m")

        now = datetime.now(UTC)
        expected_from = now - timedelta(days=30)

        assert abs((engine.from_date - expected_from).total_seconds()) < 5

    def test_time_period_week(self):
        """Test time period set to 1 week."""
        from local_deep_research.web_search_engines.engines.search_engine_wikinews import (
            WikinewsSearchEngine,
        )

        engine = WikinewsSearchEngine(time_period="w")

        now = datetime.now(UTC)
        expected_from = now - timedelta(days=7)

        assert abs((engine.from_date - expected_from).total_seconds()) < 5

    def test_time_period_day(self):
        """Test time period set to 1 day."""
        from local_deep_research.web_search_engines.engines.search_engine_wikinews import (
            WikinewsSearchEngine,
        )

        engine = WikinewsSearchEngine(time_period="d")

        now = datetime.now(UTC)
        expected_from = now - timedelta(days=1)

        assert abs((engine.from_date - expected_from).total_seconds()) < 5

    def test_original_date_range_preserved(self):
        """Test that original date range is preserved for restoration."""
        from local_deep_research.web_search_engines.engines.search_engine_wikinews import (
            WikinewsSearchEngine,
        )

        engine = WikinewsSearchEngine(time_period="m")

        assert engine._original_date_range is not None
        assert engine._original_date_range[0] == engine.from_date
        assert engine._original_date_range[1] == engine.to_date


class TestWikinewsEngineType:
    """Tests for WikiNews engine type identification."""

    def test_engine_type_set(self):
        """Test that engine type is properly set."""
        from local_deep_research.web_search_engines.engines.search_engine_wikinews import (
            WikinewsSearchEngine,
        )

        engine = WikinewsSearchEngine()
        assert "wikinews" in engine.engine_type.lower()

    def test_engine_is_public(self):
        """Test that engine is marked as public."""
        from local_deep_research.web_search_engines.engines.search_engine_wikinews import (
            WikinewsSearchEngine,
        )

        engine = WikinewsSearchEngine()
        assert engine.is_public is True

    def test_engine_is_news(self):
        """Test that engine is marked as news source."""
        from local_deep_research.web_search_engines.engines.search_engine_wikinews import (
            WikinewsSearchEngine,
        )

        engine = WikinewsSearchEngine()
        assert engine.is_news is True


class TestWikinewsQueryOptimization:
    """Tests for WikiNews query optimization."""

    @pytest.fixture
    def engine(self):
        """Create a WikiNews engine."""
        from local_deep_research.web_search_engines.engines.search_engine_wikinews import (
            WikinewsSearchEngine,
        )

        return WikinewsSearchEngine()

    def test_optimize_query_without_llm(self, engine):
        """Test that original query is returned without LLM."""
        engine.llm = None
        result = engine._optimize_query_for_wikinews(
            "What is happening with AI regulations?"
        )
        assert result == "What is happening with AI regulations?"

    def test_optimize_query_with_llm_success(self, engine):
        """Test query optimization with LLM."""
        mock_llm = Mock()
        mock_llm.invoke = Mock(
            return_value=Mock(content='{"query": "AI regulations"}')
        )
        engine.llm = mock_llm

        result = engine._optimize_query_for_wikinews(
            "What is happening with AI regulations?"
        )
        assert result == "AI regulations"

    def test_optimize_query_with_llm_invalid_json(self, engine):
        """Test that invalid JSON from LLM returns original query."""
        mock_llm = Mock()
        mock_llm.invoke = Mock(return_value=Mock(content="not valid json"))
        engine.llm = mock_llm

        result = engine._optimize_query_for_wikinews("test query")
        assert result == "test query"

    def test_optimize_query_with_llm_empty_query(self, engine):
        """Test that empty optimized query returns original."""
        mock_llm = Mock()
        mock_llm.invoke = Mock(return_value=Mock(content='{"query": ""}'))
        engine.llm = mock_llm

        result = engine._optimize_query_for_wikinews("original query")
        assert result == "original query"


class TestWikinewsDateAdaptation:
    """Tests for WikiNews date adaptation logic."""

    @pytest.fixture
    def engine(self):
        """Create a WikiNews engine with adaptive search enabled."""
        from local_deep_research.web_search_engines.engines.search_engine_wikinews import (
            WikinewsSearchEngine,
        )

        return WikinewsSearchEngine(adaptive_search=True, time_period="y")

    def test_adapt_dates_resets_to_original(self, engine):
        """Test that date adaptation resets to original first."""
        # Modify dates
        engine.from_date = datetime.now(UTC)
        engine.to_date = datetime.now(UTC)

        # Adapt dates (should reset first)
        engine._adapt_date_range_for_query("short")

        # Should reset to original values
        assert engine.from_date == engine._original_date_range[0]
        assert engine.to_date == engine._original_date_range[1]

    def test_adapt_dates_short_query_no_adaptation(self, engine):
        """Test that short queries don't trigger adaptation."""
        engine.llm = Mock()
        original_from = engine.from_date

        engine._adapt_date_range_for_query("AI news")

        # Short queries (<= 4 words) should not adapt
        assert engine.from_date == original_from

    def test_adapt_dates_without_llm(self, engine):
        """Test that dates are not adapted without LLM."""
        engine.llm = None
        original_from = engine.from_date

        engine._adapt_date_range_for_query(
            "This is a longer query about current events"
        )

        assert engine.from_date == original_from

    def test_adapt_dates_without_adaptive_search(self, engine):
        """Test that dates are not adapted when adaptive search is disabled."""
        engine.adaptive_search = False
        engine.llm = Mock()
        original_from = engine.from_date

        engine._adapt_date_range_for_query(
            "This is a longer query about current events"
        )

        assert engine.from_date == original_from

    def test_adapt_dates_current_events(self, engine):
        """Test date adaptation for current events."""
        mock_llm = Mock()
        mock_llm.invoke = Mock(return_value=Mock(content="CURRENT"))
        engine.llm = mock_llm

        engine._adapt_date_range_for_query(
            "What are the latest developments in technology today?"
        )

        # Should be set to recent (60 days default)
        expected_from = datetime.now(UTC) - timedelta(days=60)
        assert abs((engine.from_date - expected_from).total_seconds()) < 5

    def test_adapt_dates_historical_events(self, engine):
        """Test date adaptation for historical events."""
        mock_llm = Mock()
        mock_llm.invoke = Mock(return_value=Mock(content="HISTORICAL"))
        engine.llm = mock_llm

        engine._adapt_date_range_for_query(
            "What happened during the 2008 financial crisis?"
        )

        # Should be set to datetime.min (very old)
        assert engine.from_date.year == 1


class TestWikinewsSearchExecution:
    """Tests for WikiNews search execution."""

    @pytest.fixture
    def engine(self):
        """Create a WikiNews engine."""
        from local_deep_research.web_search_engines.engines.search_engine_wikinews import (
            WikinewsSearchEngine,
        )

        return WikinewsSearchEngine(max_results=5, adaptive_search=False)

    def test_fetch_search_results_success(self, engine, monkeypatch):
        """Test successful search results fetching."""
        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.raise_for_status = Mock()
        mock_response.json = Mock(
            return_value={
                "query": {
                    "search": [
                        {
                            "pageid": 12345,
                            "title": "Test News Article",
                            "snippet": "This is a <span>test</span> snippet",
                            "timestamp": "2024-01-15T10:00:00Z",
                        }
                    ]
                }
            }
        )

        monkeypatch.setattr(
            "local_deep_research.web_search_engines.engines.search_engine_wikinews.requests.get",
            Mock(return_value=mock_response),
        )

        results = engine._fetch_search_results("test query", 0)

        assert len(results) == 1
        assert results[0]["title"] == "Test News Article"

    def test_fetch_search_results_empty(self, engine, monkeypatch):
        """Test search results fetching with no results."""
        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.raise_for_status = Mock()
        mock_response.json = Mock(return_value={"query": {"search": []}})

        monkeypatch.setattr(
            "local_deep_research.web_search_engines.engines.search_engine_wikinews.requests.get",
            Mock(return_value=mock_response),
        )

        results = engine._fetch_search_results("nonexistent topic", 0)

        assert results == []

    def test_fetch_search_results_handles_exception(self, engine, monkeypatch):
        """Test that exceptions are handled gracefully after retries."""
        # The function retries 3 times (MAX_RETRIES), so we need to handle all attempts
        import requests

        monkeypatch.setattr(
            "local_deep_research.web_search_engines.engines.search_engine_wikinews.requests.get",
            Mock(
                side_effect=requests.exceptions.RequestException(
                    "Network error"
                )
            ),
        )

        results = engine._fetch_search_results("test query", 0)
        assert results == []


class TestWikinewsSnippetCleaning:
    """Tests for WikiNews snippet cleaning."""

    def test_clean_snippet_removes_html(self):
        """Test that HTML tags are removed from snippets."""
        from local_deep_research.web_search_engines.engines.search_engine_wikinews import (
            _clean_wikinews_snippet,
        )

        snippet = "This is <span class='highlight'>highlighted</span> text"
        result = _clean_wikinews_snippet(snippet)
        assert result == "This is highlighted text"

    def test_clean_snippet_unescapes_html_entities(self):
        """Test that HTML entities are unescaped."""
        from local_deep_research.web_search_engines.engines.search_engine_wikinews import (
            _clean_wikinews_snippet,
        )

        snippet = "Tom &amp; Jerry &lt;3 animation"
        result = _clean_wikinews_snippet(snippet)
        assert result == "Tom & Jerry <3 animation"

    def test_clean_snippet_normalizes_whitespace(self):
        """Test that whitespace is normalized."""
        from local_deep_research.web_search_engines.engines.search_engine_wikinews import (
            _clean_wikinews_snippet,
        )

        snippet = "Too   many     spaces"
        result = _clean_wikinews_snippet(snippet)
        assert result == "Too many spaces"

    def test_clean_snippet_handles_empty(self):
        """Test that empty snippet returns empty string."""
        from local_deep_research.web_search_engines.engines.search_engine_wikinews import (
            _clean_wikinews_snippet,
        )

        assert _clean_wikinews_snippet("") == ""
        assert _clean_wikinews_snippet(None) == ""


class TestWikinewsAPIConfiguration:
    """Tests for WikiNews API configuration."""

    def test_api_url_template(self):
        """Test that API URL template is correctly set."""
        from local_deep_research.web_search_engines.engines.search_engine_wikinews import (
            WikinewsSearchEngine,
        )

        engine = WikinewsSearchEngine()
        assert "{lang_code}" in engine.api_url

    def test_api_url_english(self):
        """Test API URL for English WikiNews."""
        from local_deep_research.web_search_engines.engines.search_engine_wikinews import (
            WikinewsSearchEngine,
        )

        engine = WikinewsSearchEngine(search_language="english")
        formatted_url = engine.api_url.format(lang_code=engine.lang_code)
        assert "en.wikinews.org" in formatted_url

    def test_api_url_german(self):
        """Test API URL for German WikiNews."""
        from local_deep_research.web_search_engines.engines.search_engine_wikinews import (
            WikinewsSearchEngine,
        )

        engine = WikinewsSearchEngine(search_language="german")
        formatted_url = engine.api_url.format(lang_code=engine.lang_code)
        assert "de.wikinews.org" in formatted_url


class TestWikinewsFullContent:
    """Tests for WikiNews full content retrieval."""

    def test_get_full_content_returns_items(self):
        """Test that full content returns the same items."""
        from local_deep_research.web_search_engines.engines.search_engine_wikinews import (
            WikinewsSearchEngine,
        )

        engine = WikinewsSearchEngine()

        items = [
            {
                "id": 12345,
                "title": "Test Article",
                "snippet": "Test snippet",
                "content": "Full content here",
            }
        ]

        results = engine._get_full_content(items)

        assert results == items


class TestWikinewsSupportedLanguages:
    """Tests for WikiNews supported languages."""

    def test_supported_languages_list(self):
        """Test that supported languages list is defined."""
        from local_deep_research.web_search_engines.engines.search_engine_wikinews import (
            WIKINEWS_LANGUAGES,
        )

        assert isinstance(WIKINEWS_LANGUAGES, list)
        assert "en" in WIKINEWS_LANGUAGES
        assert "de" in WIKINEWS_LANGUAGES
        assert "fr" in WIKINEWS_LANGUAGES
        assert "es" in WIKINEWS_LANGUAGES
