"""Tests for Catholic search, apologetics, commentary, and cross-reference chains."""
from __future__ import annotations
import pytest

# --- Canon ---
try:
    from accordance_parser.canon import (
        parse_reference, resolve_book, CANON_CATHOLIC,
        chapter_count, last_verse_of_chapter, canon_by_name,
    )
    _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

# --- Morphology ---
try:
    from accordance_parser.morphology import describe_robinson
    _has_morphology = True
except Exception:
    _has_morphology = False

# --- Search index ---
try:
    _has_search = True
except Exception:
    _has_search = False

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


# =====================================================================
# LOCAL TESTS — Catholic canon for apologetic passages (no network needed)
# =====================================================================

@pytest.mark.skipif(not _has_canon, reason="Canon not available")
class TestCatholicApologeticReferences:
    """S-P-9, S-P-11, S-T-4, S-T-7, S-T-12, S-L-6, S-L-8, S-L-10: Reference parsing."""

    # --- Mary / Magnificat ---
    def test_luke_1_46(self):
        r = parse_reference("Luke 1:46", "catholic")
        assert r is not None

    def test_luke_1_28(self):
        r = parse_reference("Luke 1:28", "catholic")
        assert r is not None

    def test_luke_1_43(self):
        r = parse_reference("Luke 1:43", "catholic")
        assert r is not None

    def test_luke_1_39(self):
        r = parse_reference("Luke 1:39", "catholic")
        assert r is not None

    def test_luke_1_56(self):
        r = parse_reference("Luke 1:56", "catholic")
        assert r is not None

    def test_luke_1_35(self):
        r = parse_reference("Luke 1:35", "catholic")
        assert r is not None

    # --- Saints / Revelation ---
    def test_revelation_5_8(self):
        r = parse_reference("Revelation 5:8", "catholic")
        assert r is not None

    def test_revelation_12_1(self):
        r = parse_reference("Revelation 12:1", "catholic")
        assert r is not None

    def test_romans_1_7(self):
        r = parse_reference("Romans 1:7", "catholic")
        assert r is not None

    # --- Peter / Papacy ---
    def test_matthew_16_18(self):
        r = parse_reference("Matthew 16:18", "catholic")
        assert r is not None

    # --- Confession / Sacraments ---
    def test_john_20_23(self):
        r = parse_reference("John 20:23", "catholic")
        assert r is not None

    def test_james_5_16(self):
        r = parse_reference("James 5:16", "catholic")
        assert r is not None

    def test_1peter_3_21(self):
        r = parse_reference("1 Peter 3:21", "catholic")
        assert r is not None

    # --- Tradition ---
    def test_2thess_2_15(self):
        r = parse_reference("2 Thessalonians 2:15", "catholic")
        assert r is not None

    # --- Faith and works ---
    def test_james_2_24(self):
        r = parse_reference("James 2:24", "catholic")
        assert r is not None

    # --- Hebrews catena (S-T-4) ---
    def test_hebrews_1_5(self):
        r = parse_reference("Hebrews 1:5", "catholic")
        assert r is not None

    def test_psalm_2_7(self):
        r = parse_reference("Psalms 2:7", "catholic")
        assert r is not None

    def test_deut_32_43(self):
        r = parse_reference("Deuteronomy 32:43", "catholic")
        assert r is not None

    def test_psalm_104_4(self):
        r = parse_reference("Psalms 104:4", "catholic")
        assert r is not None

    def test_psalm_45_6(self):
        r = parse_reference("Psalm 45:6", "catholic")
        assert r is not None

    def test_psalm_110_1(self):
        r = parse_reference("Psalms 110:1", "catholic")
        assert r is not None

    # --- Protoevangelium (S-T-7) ---
    def test_genesis_3_15(self):
        r = parse_reference("Genesis 3:15", "catholic")
        assert r is not None

    # --- Melchizedek (S-T-12) ---
    def test_genesis_14_18(self):
        r = parse_reference("Genesis 14:18", "catholic")
        assert r is not None

    def test_hebrews_7_3(self):
        r = parse_reference("Hebrews 7:3", "catholic")
        assert r is not None

    # --- Mary as Ark (S-L-6) ---
    def test_2sam_6_9(self):
        r = parse_reference("2 Samuel 6:9", "catholic")
        assert r is not None

    def test_exodus_40_34(self):
        r = parse_reference("Exodus 40:34", "catholic")
        assert r is not None

    # --- Romans 8 (S-L-8) ---
    def test_romans_8_1(self):
        r = parse_reference("Romans 8:1", "catholic")
        assert r is not None

    def test_romans_8_28(self):
        r = parse_reference("Romans 8:28", "catholic")
        assert r is not None

    def test_romans_8_39(self):
        r = parse_reference("Romans 8:39", "catholic")
        assert r is not None

    # --- Deutero (S-L-10 RCIA) ---
    def test_tobit_12_12(self):
        r = parse_reference("Tobit 12:12", "catholic")
        assert r is not None

    def test_2macc_12_46(self):
        r = parse_reference("2 Maccabees 12:46", "catholic")
        assert r is not None


@pytest.mark.skipif(not _has_canon, reason="Canon not available")
class TestCatholicCanonStructure:
    """Canon structural tests for apologetic verification."""

    def test_catholic_has_73(self):
        assert len(CANON_CATHOLIC.books) == 73

    def test_catholic_includes_deuterocanonicals(self):
        names = {b.osis for b in CANON_CATHOLIC.books}
        for d in ["Tob", "Jdt", "1Macc", "2Macc", "Wis", "Sir", "Bar"]:
            assert d in names, f"{d} missing from Catholic canon"

    def test_romans_has_16_chapters_catholic(self):
        ch = chapter_count("Rom", CANON_CATHOLIC)
        assert ch == 16

    def test_romans_8_has_39_verses(self):
        last = last_verse_of_chapter("Rom", 8, CANON_CATHOLIC)
        assert last == 39

    def test_luke_has_24_chapters(self):
        ch = chapter_count("Luke", CANON_CATHOLIC)
        assert ch == 24

    def test_hebrews_has_13_chapters(self):
        ch = chapter_count("Heb", CANON_CATHOLIC)
        assert ch == 13

    def test_psalms_has_150_chapters(self):
        ch = chapter_count("Ps", CANON_CATHOLIC)
        assert ch == 150

    def test_genesis_has_50_chapters(self):
        ch = chapter_count("Gen", CANON_CATHOLIC)
        assert ch == 50

    def test_exodus_has_40_chapters(self):
        ch = chapter_count("Exod", CANON_CATHOLIC)
        assert ch == 40

    def test_deuteronomy_has_34_chapters(self):
        ch = chapter_count("Deut", CANON_CATHOLIC)
        assert ch == 34

    def test_revelation_has_22_chapters(self):
        ch = chapter_count("Rev", CANON_CATHOLIC)
        assert ch == 22

    def test_john_has_21_chapters(self):
        ch = chapter_count("John", CANON_CATHOLIC)
        assert ch == 21

    def test_matthew_has_28_chapters(self):
        ch = chapter_count("Matt", CANON_CATHOLIC)
        assert ch == 28


@pytest.mark.skipif(not _has_canon, reason="Canon not available")
class TestBookNameResolution:
    """Test resolve_book for key Catholic-apologetic books."""

    def test_resolve_genesis(self):
        b = resolve_book("Genesis")
        assert b is not None
        assert b.osis == "Gen"

    def test_resolve_exodus(self):
        b = resolve_book("Exodus")
        assert b is not None
        assert b.osis == "Exod"

    def test_resolve_psalm(self):
        b = resolve_book("Psalm")
        assert b is not None

    def test_resolve_matthew(self):
        b = resolve_book("Matthew")
        assert b is not None
        assert b.osis == "Matt"

    def test_resolve_luke(self):
        b = resolve_book("Luke")
        assert b is not None
        assert b.osis == "Luke"

    def test_resolve_john(self):
        b = resolve_book("John")
        assert b is not None

    def test_resolve_romans(self):
        b = resolve_book("Romans")
        assert b is not None
        assert b.osis == "Rom"

    def test_resolve_hebrews(self):
        b = resolve_book("Hebrews")
        assert b is not None
        assert b.osis == "Heb"

    def test_resolve_revelation(self):
        b = resolve_book("Revelation")
        assert b is not None
        assert b.osis == "Rev"

    def test_resolve_james(self):
        b = resolve_book("James")
        assert b is not None
        assert b.osis == "Jas"

    def test_resolve_1corinthians(self):
        b = resolve_book("1 Corinthians")
        assert b is not None

    def test_resolve_2samuel(self):
        b = resolve_book("2 Samuel")
        assert b is not None

    def test_resolve_tobit(self):
        b = resolve_book("Tobit")
        assert b is not None

    def test_resolve_2macc(self):
        b = resolve_book("2 Maccabees")
        assert b is not None

    def test_canon_by_name_returns_correct(self):
        c = canon_by_name("catholic")
        assert len(c.books) == 73
        p = canon_by_name("protestant")
        assert len(p.books) == 66


# =====================================================================
# MORPHOLOGY TESTS (local)
# =====================================================================

@pytest.mark.skipif(not _has_morphology, reason="Morphology not available")
class TestApologeticMorphology:
    """S-L-5, S-P-9: Morphology code descriptions for apologetic passages."""

    def test_present_active_participle(self):
        desc = describe_robinson("V-PAP-NSM")
        assert "Present" in desc or "Participle" in desc

    def test_aorist_active(self):
        desc = describe_robinson("V-AAI-3S")
        assert "Aorist" in desc

    def test_perfect_active(self):
        desc = describe_robinson("V-XAI-3S")
        assert "Perfect" in desc

    def test_nominative_masculine(self):
        desc = describe_robinson("N-NSM")
        assert len(desc) > 0

    def test_dative_feminine(self):
        desc = describe_robinson("N-DSF")
        assert len(desc) > 0

    def test_adjective_dative_plural(self):
        desc = describe_robinson("A-DPM")
        assert "Dative" in desc or "Plural" in desc


# =====================================================================
# NETWORK TESTS
# =====================================================================

@pytest.mark.skipif(not _has_network, reason="Requires network")
class TestVerseRetrievalApologetic:
    """Key verses for Catholic apologetics."""

    def test_matthew_16_18_nabre(self):
        r = get_verse("Matthew 16:18", "NABRE")
        assert r is not None
        assert "Peter" in r.text or "rock" in r.text.lower()

    def test_luke_1_28_nabre(self):
        r = get_verse("Luke 1:28", "NABRE")
        assert r is not None
        assert "favored" in r.text.lower() or "hail" in r.text.lower() or len(r.text) > 5

    def test_romans_8_28_nabre(self):
        r = get_verse("Romans 8:28", "NABRE")
        assert r is not None
        assert "good" in r.text.lower() or "God" in r.text

    def test_genesis_3_15_nabre(self):
        r = get_verse("Genesis 3:15", "NABRE")
        assert r is not None
        assert "serpent" in r.text.lower() or "woman" in r.text.lower()

    def test_2macc_12_46_nabre(self):
        r = get_verse("2 Maccabees 12:46", "NABRE")
        assert r is not None
