"""Tests for Catholic canon boundaries and deuterocanonical book handling."""
from __future__ import annotations
import pytest

# --- Canon imports ---
try:
    from accordance_parser.canon import (
        resolve_book, parse_reference, CANON_PROTESTANT, CANON_CATHOLIC,
        chapter_count, last_verse_of_chapter,
    )
    _has_canon = True
except Exception:
    _has_canon = False

# --- Bible API ---
try:
    from accordance_parser.bible_api import get_verse
    _has_bible_api = True
except Exception:
    _has_bible_api = False

# --- MCP tools ---
try:
    _has_mcp = True
except Exception:
    try:
        _has_mcp = True
    except Exception:
        _has_mcp = False

# --- Network detection ---
_has_network = False
try:
    from accordance_parser.bible_api import get_verse
    result = get_verse("Genesis 1:1", "KJV")
    if result and result.text:
        _has_network = True
except Exception:
    pass

# =====================================================================
# LOCAL-ONLY TESTS (should always pass)
# =====================================================================

@pytest.mark.skipif(not _has_canon, reason="canon module not available")
class TestCatholicCanonBoundaries:
    """S-P-3, S-P-10, S-L-2: Catholic canon enumeration and deuterocanonical inclusion."""

    def test_catholic_canon_has_73_books(self):
        """Catholic canon should contain 73 books."""
        assert len(CANON_CATHOLIC.books) == 73

    def test_protestant_canon_has_66_books(self):
        """Protestant canon should contain 66 books."""
        assert len(CANON_PROTESTANT.books) == 66

    def test_tobit_in_catholic_not_protestant(self):
        cath_names = {b.osis for b in CANON_CATHOLIC.books}
        prot_names = {b.osis for b in CANON_PROTESTANT.books}
        assert "Tob" in cath_names
        assert "Tob" not in prot_names

    def test_judith_in_catholic_not_protestant(self):
        cath_names = {b.osis for b in CANON_CATHOLIC.books}
        prot_names = {b.osis for b in CANON_PROTESTANT.books}
        assert "Jdt" in cath_names
        assert "Jdt" not in prot_names

    def test_wisdom_in_catholic_not_protestant(self):
        cath_names = {b.osis for b in CANON_CATHOLIC.books}
        prot_names = {b.osis for b in CANON_PROTESTANT.books}
        assert "Wis" in cath_names
        assert "Wis" not in prot_names

    def test_sirach_in_catholic_not_protestant(self):
        cath_names = {b.osis for b in CANON_CATHOLIC.books}
        prot_names = {b.osis for b in CANON_PROTESTANT.books}
        assert "Sir" in cath_names
        assert "Sir" not in prot_names

    def test_baruch_in_catholic_not_protestant(self):
        cath_names = {b.osis for b in CANON_CATHOLIC.books}
        prot_names = {b.osis for b in CANON_PROTESTANT.books}
        assert "Bar" in cath_names
        assert "Bar" not in prot_names

    def test_1macc_in_catholic_not_protestant(self):
        cath_names = {b.osis for b in CANON_CATHOLIC.books}
        prot_names = {b.osis for b in CANON_PROTESTANT.books}
        assert "1Macc" in cath_names
        assert "1Macc" not in prot_names

    def test_2macc_in_catholic_not_protestant(self):
        cath_names = {b.osis for b in CANON_CATHOLIC.books}
        prot_names = {b.osis for b in CANON_PROTESTANT.books}
        assert "2Macc" in cath_names
        assert "2Macc" not in prot_names

    def test_daniel_14_chapters_catholic(self):
        """Catholic Daniel has 14 chapters (vs 12 Protestant)."""
        ch = chapter_count("Dan", CANON_CATHOLIC)
        assert ch == 14

    def test_daniel_12_chapters_protestant(self):
        ch = chapter_count("Dan", CANON_PROTESTANT)
        assert ch == 12

    def test_sirach_chapter_count(self):
        """Sirach has 51 chapters."""
        ch = chapter_count("Sir", CANON_CATHOLIC)
        assert ch == 51

    def test_tobit_chapter_count(self):
        ch = chapter_count("Tob", CANON_CATHOLIC)
        assert ch == 14

    def test_wisdom_chapter_count(self):
        ch = chapter_count("Wis", CANON_CATHOLIC)
        assert ch == 19

    def test_judith_chapter_count(self):
        ch = chapter_count("Jdt", CANON_CATHOLIC)
        assert ch == 16

    def test_baruch_chapter_count(self):
        """Baruch has 6 chapters (ch 6 = Letter of Jeremiah)."""
        ch = chapter_count("Bar", CANON_CATHOLIC)
        assert ch == 6

    def test_1macc_chapter_count(self):
        ch = chapter_count("1Macc", CANON_CATHOLIC)
        assert ch == 16

    def test_2macc_chapter_count(self):
        ch = chapter_count("2Macc", CANON_CATHOLIC)
        assert ch == 15

    def test_catholic_verse_count_greater_than_protestant(self):
        cath_total = sum(
            last_verse_of_chapter(book.osis, ch, CANON_CATHOLIC)
            for book in CANON_CATHOLIC.books
            for ch in range(1, chapter_count(book.osis, CANON_CATHOLIC) + 1)
        )
        prot_total = sum(
            last_verse_of_chapter(book.osis, ch, CANON_PROTESTANT)
            for book in CANON_PROTESTANT.books
            for ch in range(1, chapter_count(book.osis, CANON_PROTESTANT) + 1)
        )
        assert cath_total > prot_total


@pytest.mark.skipif(not _has_canon, reason="canon module not available")
class TestDeuterocanonicalReferenceParsing:
    """S-P-4, S-P-6, S-L-11: Reference parsing for deuterocanonical books."""

    def test_parse_tobit_ref(self):
        """parse_reference should handle 'Tobit 8:4'."""
        result = parse_reference("Tobit 8:4", "catholic")
        assert result is not None
        assert result.book_osis == "Tob"
        assert result.chapter == 8
        assert result.verse == 4

    def test_parse_wisdom_ref(self):
        result = parse_reference("Wisdom 3:1", "catholic")
        assert result is not None
        assert result.book_osis == "Wis"
        assert result.chapter == 3
        assert result.verse == 1

    def test_parse_sirach_ref(self):
        result = parse_reference("Sirach 1:1", "catholic")
        assert result is not None
        assert result.book_osis == "Sir"
        assert result.chapter == 1
        assert result.verse == 1

    def test_parse_1macc_ref(self):
        result = parse_reference("1 Maccabees 2:1", "catholic")
        assert result is not None
        assert result.book_osis == "1Macc"
        assert result.chapter == 2

    def test_parse_2macc_ref(self):
        result = parse_reference("2 Maccabees 12:46", "catholic")
        assert result is not None
        assert result.book_osis == "2Macc"
        assert result.chapter == 12
        assert result.verse == 46

    def test_parse_baruch_ref(self):
        result = parse_reference("Baruch 6:1", "catholic")
        assert result is not None
        assert result.book_osis == "Bar"
        assert result.chapter == 6

    def test_parse_judith_ref(self):
        result = parse_reference("Judith 16:25", "catholic")
        assert result is not None
        assert result.book_osis == "Jdt"
        assert result.chapter == 16
        assert result.verse == 25

    def test_deutero_ref_not_in_protestant(self):
        """Deuterocanonical reference — parsing should not crash in Protestant mode."""
        result = parse_reference("Tobit 1:1", "protestant")
        assert result is not None  # Parse doesn't crash, even if not in canon

    def test_resolve_book_tobit(self):
        assert resolve_book("Tobit") is not None
        assert resolve_book("Tobit").osis == "Tob"

    def test_resolve_book_wisdom(self):
        assert resolve_book("Wisdom") is not None
        assert resolve_book("Wisdom").osis == "Wis"

    def test_resolve_book_sirach(self):
        result = resolve_book("Sirach")
        assert result is not None
        assert result.osis == "Sir"

    def test_resolve_book_baruch(self):
        result = resolve_book("Baruch")
        assert result is not None
        assert result.osis == "Bar"

    def test_resolve_book_maccabees(self):
        assert resolve_book("1 Maccabees") is not None
        assert resolve_book("2 Maccabees") is not None

    def test_nabre_name_resolution(self):
        """NABRE uses '1Mc' for 1 Maccabees; test resolve_book handles it."""
        r1 = resolve_book("1Mc")
        # At least one form should resolve
        assert r1 is not None or resolve_book("1Macc") is not None


@pytest.mark.skipif(not _has_canon, reason="canon module not available")
class TestDeuterocanonicalBoundaryValidation:
    """S-P-12, S-L-12: Out-of-bounds deuterocanonical verses."""

    def test_daniel_14_last_verse_catholic(self):
        """Verify Catholic Daniel 14 has verses."""
        last = last_verse_of_chapter("Dan", 14, CANON_CATHOLIC)
        assert last > 0
        assert last <= 50  # Bel and the Dragon is short

    def test_sirach_last_verse(self):
        last = last_verse_of_chapter("Sir", 51, CANON_CATHOLIC)
        assert last > 0
        assert last <= 40  # Sirach 51 has ~30 verses

    def test_baruch_6_last_verse(self):
        """Baruch ch 6 (Letter of Jeremiah) has verses."""
        last = last_verse_of_chapter("Bar", 6, CANON_CATHOLIC)
        assert last > 0

    def test_tobit_chapter_0_invalid(self):
        """Chapter 0 should return 0 or similar for any book."""
        try:
            v = last_verse_of_chapter("Tob", 0, CANON_CATHOLIC)
            assert v == 0
        except (IndexError, KeyError):
            pass  # acceptable


# =====================================================================
# NETWORK-DEPENDENT TESTS
# =====================================================================

@pytest.mark.skipif(not _has_network or not _has_bible_api, reason="Requires network")
class TestDeuterocanonicalVerseRetrieval:
    """S-P-3, S-P-4, S-P-6: NABRE verse retrieval for deuterocanonicals."""

    def test_nabre_tobit_8_4(self):
        result = get_verse("Tobit 8:4", "NABRE")
        assert result is not None
        assert len(result.text) > 10
        assert "pray" in result.text.lower() or "wife" in result.text.lower()

    def test_nabre_wisdom_3_1(self):
        result = get_verse("Wisdom 3:1", "NABRE")
        assert result is not None
        assert len(result.text) > 10
        assert "souls" in result.text.lower() or "righteous" in result.text.lower()

    def test_nabre_sirach_1_1(self):
        result = get_verse("Sirach 1:1", "NABRE")
        assert result is not None
        assert len(result.text) > 5

    def test_nabre_2macc_12_46(self):
        result = get_verse("2 Maccabees 12:46", "NABRE")
        assert result is not None
        assert len(result.text) > 5

    def test_nabre_daniel_14_1(self):
        """Catholic Daniel 14 (Bel and the Dragon)."""
        result = get_verse("Daniel 14:1", "NABRE")
        assert result is not None
        assert len(result.text) > 5

    def test_nabre_judith_16_25(self):
        """Last verse of Judith."""
        result = get_verse("Judith 16:25", "NABRE")
        assert result is not None
        assert len(result.text) > 5

    def test_nabre_hebrews_11_35_maccabean_ref(self):
        """Hebrews 11:35 refers to Maccabean martyrs."""
        result = get_verse("Hebrews 11:35", "NABRE")
        assert result is not None
        assert "tortured" in result.text.lower() or "resurrection" in result.text.lower()

    def test_nabre_baruch_6_1(self):
        """Baruch 6 (Letter of Jeremiah)."""
        result = get_verse("Baruch 6:1", "NABRE")
        assert result is not None
        assert len(result.text) > 5
