"""Tests for the Wikipedia service module."""
import pytest
from unittest.mock import AsyncMock, MagicMock, patch

from fabledassistant.services.wikipedia import wiki_summary, wiki_search


def _make_mock_response(json_data: dict, status_code: int = 200) -> MagicMock:
    mock_resp = MagicMock()
    mock_resp.status_code = status_code
    mock_resp.json.return_value = json_data
    mock_resp.raise_for_status = MagicMock()
    return mock_resp


@pytest.mark.asyncio
async def test_wiki_summary_returns_extract():
    """Successful lookup returns a dict with title, extract, and url."""
    payload = {
        "type": "standard",
        "title": "Python (programming language)",
        "extract": "Python is a high-level programming language.",
        "content_urls": {"desktop": {"page": "https://en.wikipedia.org/wiki/Python_(programming_language)"}},
    }
    mock_resp = _make_mock_response(payload)

    with patch("fabledassistant.services.wikipedia.httpx.AsyncClient") as mock_client_cls:
        mock_client = AsyncMock()
        mock_client.__aenter__ = AsyncMock(return_value=mock_client)
        mock_client.__aexit__ = AsyncMock(return_value=False)
        mock_client.get = AsyncMock(return_value=mock_resp)
        mock_client_cls.return_value = mock_client

        result = await wiki_summary("Python programming language")

    assert result is not None
    assert result["title"] == "Python (programming language)"
    assert "Python" in result["extract"]
    assert result["url"].startswith("https://")
    assert result["thumbnail_url"] == ""


@pytest.mark.asyncio
async def test_wiki_summary_includes_thumbnail():
    """Thumbnail URL is extracted when the article has an image."""
    payload = {
        "type": "standard",
        "title": "Hedgehog",
        "extract": "Hedgehogs are spiny mammals.",
        "content_urls": {"desktop": {"page": "https://en.wikipedia.org/wiki/Hedgehog"}},
        "thumbnail": {"source": "https://upload.wikimedia.org/foo-320px.jpg"},
        "originalimage": {"source": "https://upload.wikimedia.org/foo.jpg"},
    }
    mock_resp = _make_mock_response(payload)

    with patch("fabledassistant.services.wikipedia.httpx.AsyncClient") as mock_client_cls:
        mock_client = AsyncMock()
        mock_client.__aenter__ = AsyncMock(return_value=mock_client)
        mock_client.__aexit__ = AsyncMock(return_value=False)
        mock_client.get = AsyncMock(return_value=mock_resp)
        mock_client_cls.return_value = mock_client

        result = await wiki_summary("Hedgehog")

    assert result is not None
    assert result["thumbnail_url"] == "https://upload.wikimedia.org/foo-320px.jpg"


@pytest.mark.asyncio
async def test_wiki_summary_returns_none_on_404():
    """HTTP error (e.g. 404) causes wiki_summary to return None."""
    import httpx

    mock_resp = MagicMock()
    mock_resp.raise_for_status.side_effect = httpx.HTTPStatusError(
        "404", request=MagicMock(), response=MagicMock()
    )

    with patch("fabledassistant.services.wikipedia.httpx.AsyncClient") as mock_client_cls:
        mock_client = AsyncMock()
        mock_client.__aenter__ = AsyncMock(return_value=mock_client)
        mock_client.__aexit__ = AsyncMock(return_value=False)
        mock_client.get = AsyncMock(return_value=mock_resp)
        mock_client_cls.return_value = mock_client

        result = await wiki_summary("NonExistentPageXYZ123")

    assert result is None


@pytest.mark.asyncio
async def test_wiki_summary_returns_none_on_disambiguation():
    """Disambiguation pages cause wiki_summary to return None."""
    payload = {
        "type": "disambiguation",
        "title": "Mercury",
        "extract": "Mercury may refer to:",
        "content_urls": {"desktop": {"page": "https://en.wikipedia.org/wiki/Mercury"}},
    }
    mock_resp = _make_mock_response(payload)

    with patch("fabledassistant.services.wikipedia.httpx.AsyncClient") as mock_client_cls:
        mock_client = AsyncMock()
        mock_client.__aenter__ = AsyncMock(return_value=mock_client)
        mock_client.__aexit__ = AsyncMock(return_value=False)
        mock_client.get = AsyncMock(return_value=mock_resp)
        mock_client_cls.return_value = mock_client

        result = await wiki_summary("Mercury")

    assert result is None


@pytest.mark.asyncio
async def test_wiki_search_returns_results():
    """wiki_search returns a list of result dicts for a successful query."""
    search_payload = {
        "query": {
            "search": [
                {"title": "Quantum mechanics"},
                {"title": "Quantum field theory"},
            ]
        }
    }
    summary_payloads = [
        {
            "type": "standard",
            "title": "Quantum mechanics",
            "extract": "Quantum mechanics is a fundamental theory in physics.",
            "content_urls": {"desktop": {"page": "https://en.wikipedia.org/wiki/Quantum_mechanics"}},
        },
        {
            "type": "standard",
            "title": "Quantum field theory",
            "extract": "Quantum field theory is a framework in theoretical physics.",
            "content_urls": {"desktop": {"page": "https://en.wikipedia.org/wiki/Quantum_field_theory"}},
        },
    ]

    search_resp = _make_mock_response(search_payload)
    summary_resp_1 = _make_mock_response(summary_payloads[0])
    summary_resp_2 = _make_mock_response(summary_payloads[1])

    with patch("fabledassistant.services.wikipedia.httpx.AsyncClient") as mock_client_cls:
        mock_client = AsyncMock()
        mock_client.__aenter__ = AsyncMock(return_value=mock_client)
        mock_client.__aexit__ = AsyncMock(return_value=False)
        mock_client.get = AsyncMock(side_effect=[search_resp, summary_resp_1, summary_resp_2])
        mock_client_cls.return_value = mock_client

        results = await wiki_search("quantum physics", limit=2)

    assert len(results) == 2
    assert results[0]["title"] == "Quantum mechanics"
    assert "quantum" in results[0]["extract"].lower()
    assert results[1]["title"] == "Quantum field theory"


@pytest.mark.asyncio
async def test_wiki_search_returns_empty_on_failure():
    """wiki_search returns an empty list when the network request fails."""
    import httpx

    with patch("fabledassistant.services.wikipedia.httpx.AsyncClient") as mock_client_cls:
        mock_client = AsyncMock()
        mock_client.__aenter__ = AsyncMock(return_value=mock_client)
        mock_client.__aexit__ = AsyncMock(return_value=False)
        mock_client.get = AsyncMock(side_effect=httpx.ConnectError("connection refused"))
        mock_client_cls.return_value = mock_client

        results = await wiki_search("anything")

    assert results == []
