"""Tests for WideBible API client."""

from __future__ import annotations

from unittest.mock import MagicMock, patch

import pytest

from widebible import WideBible


def _mock_response(data: dict) -> MagicMock:  # type: ignore[type-arg]
    """Create a mock httpx response."""
    mock = MagicMock()
    mock.json.return_value = data
    mock.raise_for_status.return_value = None
    return mock


class TestWideBible:
    """Test WideBible API client methods."""

    def test_init_default(self) -> None:
        client = WideBible()
        assert client._client.base_url == "https://widebible.com/api/v1/bible/"
        client.close()

    def test_init_custom_base_url(self) -> None:
        client = WideBible(base_url="http://localhost:8000")
        assert client._client.base_url == "http://localhost:8000/api/v1/bible/"
        client.close()

    def test_context_manager(self) -> None:
        with WideBible() as client:
            assert client is not None

    @patch("httpx.Client.get")
    def test_list_books(self, mock_get: MagicMock) -> None:
        mock_get.return_value = _mock_response({"count": 66, "results": []})
        with WideBible() as client:
            result = client.list_books()
        assert result["count"] == 66
        mock_get.assert_called_once()

    @patch("httpx.Client.get")
    def test_get_book(self, mock_get: MagicMock) -> None:
        mock_get.return_value = _mock_response({
            "name": "Genesis",
            "slug": "genesis",
            "testament": "Old Testament",
            "chapter_count": 50,
            "verse_count": 1533,
        })
        with WideBible() as client:
            result = client.get_book("genesis")
        assert result["name"] == "Genesis"
        assert result["chapter_count"] == 50

    @patch("httpx.Client.get")
    def test_list_book_groups(self, mock_get: MagicMock) -> None:
        mock_get.return_value = _mock_response({"count": 10, "results": []})
        with WideBible() as client:
            result = client.list_book_groups()
        assert result["count"] == 10

    @patch("httpx.Client.get")
    def test_get_book_group(self, mock_get: MagicMock) -> None:
        mock_get.return_value = _mock_response({
            "name": "Pentateuch",
            "slug": "pentateuch",
            "book_count": 5,
        })
        with WideBible() as client:
            result = client.get_book_group("pentateuch")
        assert result["name"] == "Pentateuch"

    @patch("httpx.Client.get")
    def test_list_translations(self, mock_get: MagicMock) -> None:
        mock_get.return_value = _mock_response({"count": 4, "results": []})
        with WideBible() as client:
            result = client.list_translations()
        assert result["count"] == 4

    @patch("httpx.Client.get")
    def test_get_translation(self, mock_get: MagicMock) -> None:
        mock_get.return_value = _mock_response({
            "code": "kjv",
            "name": "King James Version",
            "language": "English",
            "year": 1611,
            "is_public_domain": True,
        })
        with WideBible() as client:
            result = client.get_translation("kjv")
        assert result["code"] == "kjv"
        assert result["is_public_domain"] is True

    @patch("httpx.Client.get")
    def test_list_chapters(self, mock_get: MagicMock) -> None:
        mock_get.return_value = _mock_response({"count": 50, "results": []})
        with WideBible() as client:
            result = client.list_chapters(book="genesis")
        assert result["count"] == 50

    @patch("httpx.Client.get")
    def test_get_verse(self, mock_get: MagicMock) -> None:
        mock_get.return_value = _mock_response({
            "results": [{
                "book_slug": "john",
                "book_name": "John",
                "chapter": 3,
                "verse": 16,
                "translation_code": "kjv",
                "text": "For God so loved the world...",
                "reference": "John 3:16",
            }],
        })
        with WideBible() as client:
            result = client.get_verse("john", 3, 16)
        assert result["results"][0]["reference"] == "John 3:16"

    @patch("httpx.Client.get")
    def test_search(self, mock_get: MagicMock) -> None:
        mock_get.return_value = _mock_response({
            "count": 5,
            "results": [{"reference": "John 3:16", "text": "For God so loved..."}],
        })
        with WideBible() as client:
            result = client.search("love", limit=10)
        assert result["count"] == 5

    @patch("httpx.Client.get")
    def test_list_people(self, mock_get: MagicMock) -> None:
        mock_get.return_value = _mock_response({"count": 3000, "results": []})
        with WideBible() as client:
            result = client.list_people()
        assert result["count"] == 3000

    @patch("httpx.Client.get")
    def test_get_person(self, mock_get: MagicMock) -> None:
        mock_get.return_value = _mock_response({
            "name": "Moses",
            "slug": "moses",
            "bio": "Leader of the Exodus from Egypt.",
            "testament": "Old Testament",
            "verse_count": 847,
        })
        with WideBible() as client:
            result = client.get_person("moses")
        assert result["name"] == "Moses"
        assert result["verse_count"] == 847

    @patch("httpx.Client.get")
    def test_list_places(self, mock_get: MagicMock) -> None:
        mock_get.return_value = _mock_response({"count": 942, "results": []})
        with WideBible() as client:
            result = client.list_places()
        assert result["count"] == 942

    @patch("httpx.Client.get")
    def test_get_place(self, mock_get: MagicMock) -> None:
        mock_get.return_value = _mock_response({
            "name": "Jerusalem",
            "slug": "jerusalem",
            "latitude": 31.7683,
            "longitude": 35.2137,
            "verse_count": 816,
        })
        with WideBible() as client:
            result = client.get_place("jerusalem")
        assert result["name"] == "Jerusalem"
        assert result["latitude"] == 31.7683

    @patch("httpx.Client.get")
    def test_list_topics(self, mock_get: MagicMock) -> None:
        mock_get.return_value = _mock_response({"count": 100, "results": []})
        with WideBible() as client:
            result = client.list_topics()
        assert result["count"] == 100

    @patch("httpx.Client.get")
    def test_get_topic(self, mock_get: MagicMock) -> None:
        mock_get.return_value = _mock_response({
            "name": "Love",
            "slug": "love",
            "verse_count": 310,
        })
        with WideBible() as client:
            result = client.get_topic("love")
        assert result["name"] == "Love"

    @patch("httpx.Client.get")
    def test_list_cross_references(self, mock_get: MagicMock) -> None:
        mock_get.return_value = _mock_response({"count": 432000, "results": []})
        with WideBible() as client:
            result = client.list_cross_references()
        assert result["count"] == 432000

    @patch("httpx.Client.get")
    def test_list_glossary(self, mock_get: MagicMock) -> None:
        mock_get.return_value = _mock_response({"count": 250, "results": []})
        with WideBible() as client:
            result = client.list_glossary()
        assert result["count"] == 250

    @patch("httpx.Client.get")
    def test_get_glossary_term(self, mock_get: MagicMock) -> None:
        mock_get.return_value = _mock_response({
            "term": "Covenant",
            "slug": "covenant",
            "definition": "A solemn agreement between God and humanity.",
            "hebrew_word": "berith",
        })
        with WideBible() as client:
            result = client.get_glossary_term("covenant")
        assert result["term"] == "Covenant"

    @patch("httpx.Client.get")
    def test_list_eras(self, mock_get: MagicMock) -> None:
        mock_get.return_value = _mock_response({"count": 10, "results": []})
        with WideBible() as client:
            result = client.list_eras()
        assert result["count"] == 10

    @patch("httpx.Client.get")
    def test_list_events(self, mock_get: MagicMock) -> None:
        mock_get.return_value = _mock_response({"count": 50, "results": []})
        with WideBible() as client:
            result = client.list_events(era="patriarchs")
        assert result["count"] == 50

    @patch("httpx.Client.get")
    def test_list_reading_plans(self, mock_get: MagicMock) -> None:
        mock_get.return_value = _mock_response({"count": 5, "results": []})
        with WideBible() as client:
            result = client.list_reading_plans()
        assert result["count"] == 5

    @patch("httpx.Client.get")
    def test_get_reading_plan(self, mock_get: MagicMock) -> None:
        mock_get.return_value = _mock_response({
            "name": "Bible in a Year",
            "slug": "bible-in-a-year",
            "duration_days": 365,
            "entries": [],
        })
        with WideBible() as client:
            result = client.get_reading_plan("bible-in-a-year")
        assert result["name"] == "Bible in a Year"
        assert result["duration_days"] == 365
