"""Catholic integration chain tests — multi-tool workflows across Catholic features."""
from __future__ import annotations
import pytest

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

try:
    from accordance_parser.bible_api import get_verse
    _has_bible_api = True
except Exception:
    _has_bible_api = False

try:
    from accordance_parser.morphology import describe_robinson, describe_hebrew_morph
    _has_morphology = True
except Exception:
    _has_morphology = False

try:
    from accordance_parser.lectionary import _LECTIONARY
    _has_lectionary = True
except Exception:
    _has_lectionary = False

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


# =====================================================================
# LOCAL TESTS — Lectionary → Canon → Verse resolution chains
# =====================================================================

@pytest.mark.skipif(not _has_canon, reason="Canon not available")
class TestLectionaryCanonChain:
    """SC-1, SC-5: Lectionary reading references chainable to verse resolution."""

    @pytest.mark.skipif(not _has_lectionary, reason="Lectionary not available")
    def test_lectionary_refs_parseable(self):
        """Every reading reference in the lectionary should be parseable."""
        for date_str, (title, readings) in _LECTIONARY.items():
            for key in ["first", "psalm", "gospel"]:
                if key in readings:
                    ref = readings[key]
                    if ":" in ref:
                        # Skip complex refs (comma ranges, semicolons,
                        # sub-parts, cross-chapter, slash book names)
                        if "," in ref or ";" in ref or "/" in ref:
                            continue
                        import re as _re
                        if _re.search(r"\d[a-e]", ref):
                            continue  # verse sub-parts
                        # Skip cross-chapter ranges (e.g., "5:20-6:2")
                        _dashes = "\u2013\u2014-"
                        _skip = False
                        for _d in _dashes:
                            if _d in ref and ":" in ref.split(_d, 1)[-1].strip():
                                _skip = True
                                break
                        if _skip:
                            continue
                        result = parse_reference(ref, "catholic")
                        assert result is not None, (
                            f"Failed to parse '{ref}' from {date_str} {key}"
                        )

    def test_deuterocanonical_refs_chain(self):
        """All deuterocanonical books should have parseable references."""
        deutero_books = ["Tobit", "Judith", "Wisdom", "Sirach", "Baruch",
                         "1 Maccabees", "2 Maccabees"]
        for book_name in deutero_books:
            b = resolve_book(book_name)
            assert b is not None, f"Failed to resolve {book_name}"
            assert b.osis in {bk.osis for bk in CANON_CATHOLIC.books}, (
                f"{book_name} not in Catholic canon"
            )

    def test_gospel_refs_all_resolve(self):
        """Common Gospel references should all resolve."""
        refs = [
            "John 6:53", "John 6:54", "John 20:23",
            "Luke 1:28", "Luke 1:46", "Matthew 16:18",
            "Mark 10:17", "John 3:16", "Matthew 28:19",
        ]
        for ref in refs:
            result = parse_reference(ref, "catholic")
            assert result is not None, f"Failed to parse {ref}"

    def test_ot_refs_all_resolve(self):
        """Common OT references should all resolve."""
        refs = [
            "Genesis 3:15", "Exodus 34:6", "Psalm 51:10",
            "Psalm 136:1", "Deuteronomy 6:4", "Isaiah 7:14",
            "2 Samuel 6:9", "Exodus 40:34",
        ]
        for ref in refs:
            result = parse_reference(ref, "catholic")
            assert result is not None, f"Failed to parse {ref}"

    def test_nt_epistle_refs_resolve(self):
        """NT epistle references should resolve."""
        refs = [
            "Romans 8:28", "Romans 3:23", "Romans 5:12",
            "Hebrews 11:35", "Hebrews 7:3", "Hebrews 1:5",
            "1 Corinthians 3:15", "James 2:24", "James 5:16",
            "1 Peter 3:21", "2 Thessalonians 2:15",
            "Revelation 5:8", "Revelation 12:1",
        ]
        for ref in refs:
            result = parse_reference(ref, "catholic")
            assert result is not None, f"Failed to parse {ref}"


@pytest.mark.skipif(not _has_canon, reason="Canon not available")
class TestCatholicCanonChain:
    """SC-5: Catholic canon → chapter count → verse boundary chain."""

    def test_deutero_chapter_counts_positive(self):
        """All deuterocanonical books should have positive chapter counts."""
        books = ["Tob", "Jdt", "Wis", "Sir", "Bar", "1Macc", "2Macc", "Dan"]
        for osis in books:
            ch = chapter_count(osis, CANON_CATHOLIC)
            assert ch > 0, f"{osis} has 0 chapters"

    def test_deutero_first_chapter_has_verses(self):
        """Chapter 1 of each deuterocanonical book should have verses."""
        books = ["Tob", "Jdt", "Wis", "Sir", "Bar", "1Macc", "2Macc"]
        for osis in books:
            last = last_verse_of_chapter(osis, 1, CANON_CATHOLIC)
            assert last > 0, f"{osis} chapter 1 has 0 verses"

    def test_catholic_reading_plan_day_count(self):
        """Catholic reading plan should cover 358 days (73 books)."""
        try:
            from accordance_parser.cli import _CATHOLIC_READING_PLAN
            assert len(_CATHOLIC_READING_PLAN) > 300  # Should be 358
        except ImportError:
            pass  # CLI module may not have a directly importable plan


# =====================================================================
# LOCAL TESTS — Morphology integration chains
# =====================================================================

@pytest.mark.skipif(not _has_morphology, reason="Morphology not available")
class TestMorphologyChains:
    """SC-7: Morphology descriptions integrated with reference parsing."""

    def test_robinson_tense_descriptions(self):
        """All major tenses should produce distinct descriptions."""
        tenses = {
            "V-PAI-3S": "Present",
            "V-AAI-3S": "Aorist",
            "V-XAI-3S": "Perfect",
            "V-IAI-3S": "Imperfect",
            "V-FAI-3S": "Future",
        }
        descriptions = {code: describe_robinson(code) for code in tenses}
        # Each description should contain its tense
        for code, expected in tenses.items():
            desc = descriptions[code]
            assert expected in desc, f"'{expected}' not in description for {code}: {desc}"

    def test_robinson_voice_descriptions(self):
        """Active vs Passive should produce different descriptions."""
        active_desc = describe_robinson("V-PAI-3S")
        passive_desc = describe_robinson("V-PPI-3S")
        # They should differ
        assert active_desc != passive_desc

    def test_robinson_mood_descriptions(self):
        """Indicative vs Imperative vs Subjunctive should differ."""
        ind = describe_robinson("V-PAI-3S")
        imp = describe_robinson("V-PAM-2P")
        subj = describe_robinson("V-PAS-3S")
        assert ind != imp
        assert ind != subj

    def test_noun_case_descriptions(self):
        """Different cases should produce distinct descriptions."""
        nom = describe_robinson("N-NSM")
        gen = describe_robinson("N-GSM")
        dat = describe_robinson("N-DSM")
        acc = describe_robinson("N-ASM")
        assert nom != gen
        assert nom != dat
        assert nom != acc

    def test_adjective_gender_descriptions(self):
        """Masculine, Feminine, Neuter should differ."""
        masc = describe_robinson("A-NSM")
        fem = describe_robinson("A-NSF")
        assert masc != fem

    def test_hebrew_stem_descriptions(self):
        """Hebrew stems (Qal, Niphal, Piel, Hiphil) should produce descriptions."""
        for code in ["HVqp3ms", "HVnp3ms", "HVpp3ms", "HVhp3ms"]:
            desc = describe_hebrew_morph(code)
            assert isinstance(desc, str)
            assert len(desc) > 0


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

@pytest.mark.skipif(not _has_network, reason="Requires network")
class TestVerseChaining:
    """SC-1, SC-5: Verse retrieval chains across Catholic canon."""

    def test_nabre_tobit_chain(self):
        """Tobit 8:4 → verse text → chapter context."""
        r = get_verse("Tobit 8:4", "NABRE")
        assert r is not None
        assert len(r.text) > 10
        # Should mention prayer or wife/wedding
        assert "pray" in r.text.lower() or "wife" in r.text.lower() or "tobiah" in r.text.lower()

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

    def test_nabre_john_6_chain(self):
        """Key Eucharist chain: John 6:53-54."""
        r53 = get_verse("John 6:53", "NABRE")
        r54 = get_verse("John 6:54", "NABRE")
        assert r53 is not None
        assert r54 is not None
        assert len(r53.text) > 10
        assert len(r54.text) > 10

    def test_nabre_matthew_16_chain(self):
        """Peter/Rock chain."""
        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_nabre_luke_1_chain(self):
        """Annunciation chain: Luke 1:28 and 1:46."""
        r28 = get_verse("Luke 1:28", "NABRE")
        r46 = get_verse("Luke 1:46", "NABRE")
        assert r28 is not None
        assert r46 is not None
        assert len(r28.text) > 5
        assert len(r46.text) > 5

    def test_nabre_romans_chain(self):
        """Romans 8 chain."""
        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_nabre_hebrews_chain(self):
        """Hebrews 11:35 (Maccabean martyrs)."""
        r = get_verse("Hebrews 11:35", "NABRE")
        assert r is not None
        assert "tortured" in r.text.lower() or "resurrection" in r.text.lower()

    def test_catholic_deutero_full_canon(self):
        """All deuterocanonical books should be retrievable via NABRE."""
        tests = [
            ("Tobit 1:1", "Tobit"),
            ("Judith 1:1", "Judith"),
            ("Wisdom 1:1", "Wisdom"),
            ("Sirach 1:1", "Sirach"),
            ("Baruch 1:1", "Baruch"),
            ("1 Maccabees 1:1", "Maccabees"),
            ("2 Maccabees 1:1", "Maccabees"),
        ]
        for ref, keyword in tests:
            r = get_verse(ref, "NABRE")
            assert r is not None, f"Failed to retrieve {ref}"
            assert len(r.text) > 5, f"Empty text for {ref}"
