"""
Tests for session 75 reference parsing features.

Covers:
  1. Priest #1 — Trinity Sunday comma-separated ranges
  2. Priest #3 — Psalm verse sub-parts (Baptism of the Lord)
  3. Priest #4 — Corpus Christi comma-separated ranges with sub-parts
  4. Priest #11 — Assumption semicolon + comma references
  5. Theologian #3 — Comma-separated ranges in 1 Peter
  6. Theologian #12 — Baptism of the Lord ranges
"""


from accordance_parser.canon import (
    parse_reference,
)

# Lectionary and bible_api imported inline where needed to keep
# test discovery fast when those modules are unavailable.


# =============================================================================
# Priest #1 — Trinity Sunday Comma-Separated Ranges
# =============================================================================

class TestPriest1TrinitySunday:
    """Trinity Sunday (2026-05-31): Exodus 34, Daniel 3, 2 Cor 13, John 3."""

    # -- Simple range (no comma) -------------------------------------------------

    def test_exodus_34_4_6_simple_range(self):
        """'Exodus 34:4-6' — simple range, no comma."""
        r = parse_reference("Exodus 34:4-6")
        assert r is not None
        assert r.book_osis == "Exod"
        assert r.chapter == 34
        assert r.verse == 4
        assert r.end_verse == 6
        assert r.verse_list is None  # not a comma ref

    def test_exodus_34_4_6_8_9_comma_skip(self):
        """'Exodus 34:4-6, 8-9' — comma skip-range, skipping verse 7."""
        r = parse_reference("Exodus 34:4-6, 8-9")
        assert r is not None
        assert r.book_osis == "Exod"
        assert r.chapter == 34
        assert r.verse == 4
        assert r.end_verse == 9
        assert r.verse_list == [4, 5, 6, 8, 9]

    def test_exodus_34_4b_6_8_9_with_subpart(self):
        """'Exodus 34:4b-6, 8-9' — sub-part '4b' stripped; lectionary exact."""
        r = parse_reference("Exodus 34:4b-6, 8-9")
        assert r is not None
        assert r.book_osis == "Exod"
        assert r.chapter == 34
        assert r.verse == 4
        assert r.end_verse == 9
        assert r.verse_list == [4, 5, 6, 8, 9]

    # -- Daniel comma-separated individual verses ---------------------------------

    def test_daniel_3_comma_individual_verses(self):
        """'Daniel 3:52, 53, 54, 55' — comma-separated individual verses."""
        r = parse_reference("Daniel 3:52, 53, 54, 55")
        assert r is not None
        assert r.book_osis == "Dan"
        assert r.chapter == 3
        assert r.verse == 52
        assert r.end_verse == 55
        assert r.verse_list == [52, 53, 54, 55]

    # -- NT ranges (no comma) ----------------------------------------------------

    def test_2cor_13_11_13_range(self):
        """'2 Corinthians 13:11-13' — simple hyphen range."""
        r = parse_reference("2 Corinthians 13:11-13")
        assert r is not None
        assert r.book_osis == "2Cor"
        assert r.chapter == 13
        assert r.verse == 11
        assert r.end_verse == 13
        assert r.verse_list is None

    def test_john_3_16_18_range(self):
        """'John 3:16-18' — simple hyphen range."""
        r = parse_reference("John 3:16-18")
        assert r is not None
        assert r.book_osis == "John"
        assert r.chapter == 3
        assert r.verse == 16
        assert r.end_verse == 18
        assert r.verse_list is None

    # -- Lectionary lookup --------------------------------------------------------

    def test_lectionary_trinity_sunday_2026_05_31(self):
        """Trinity Sunday 2026-05-31 has all four readings."""
        from accordance_parser.lectionary import get_lectionary_for_date_string

        result = get_lectionary_for_date_string("2026-05-31")
        assert result is not None
        season, readings = result
        assert "Trinity" in season
        assert "first" in readings
        assert "psalm" in readings
        assert "second" in readings
        assert "gospel" in readings

    def test_trinity_readings_all_parseable(self):
        """All four Trinity Sunday readings parse without error."""
        from accordance_parser.lectionary import get_lectionary_for_date_string

        _, readings = get_lectionary_for_date_string("2026-05-31")

        # first: Exodus 34:4b-6, 8-9  (comma + sub-part)
        r1 = parse_reference(readings["first"])
        assert r1 is not None
        assert r1.book_osis == "Exod"
        assert r1.verse_list is not None

        # psalm: Daniel 3:52, 53, 54, 55  (comma individual verses)
        r2 = parse_reference(readings["psalm"])
        assert r2 is not None
        assert r2.book_osis == "Dan"
        assert r2.verse_list is not None

        # second: 2 Corinthians 13:11-13 (simple range)
        r3 = parse_reference(readings["second"])
        assert r3 is not None
        assert r3.book_osis == "2Cor"

        # gospel: John 3:16-18 (simple range)
        r4 = parse_reference(readings["gospel"])
        assert r4 is not None
        assert r4.book_osis == "John"

    # -- Edge: empty / invalid ---------------------------------------------------

    def test_empty_ref_returns_none(self):
        """Empty string returns None."""
        assert parse_reference("") is None

    def test_invalid_ref_returns_none(self):
        """Unknown book returns None."""
        assert parse_reference("nonexistentbook 1:1") is None


# =============================================================================
# Priest #3 — Psalm Verse Sub-parts (Baptism of the Lord)
# =============================================================================

class TestPriest3BaptismPsalm:
    """Baptism of the Lord (2026-01-11): Psalm 29 with + and b sub-parts."""

    def test_psalm_29_full_lectionary_ref(self):
        """'Psalms 29:1-2, 3-4, 3b+9b-10' — full lectionary Psalm ref."""
        r = parse_reference("Psalms 29:1-2, 3-4, 3b+9b-10")
        assert r is not None
        assert r.book_osis == "Ps"
        assert r.chapter == 29
        assert r.verse == 1
        assert r.end_verse == 10
        # The implementation does NOT deduplicate; verse 3 appears twice
        assert r.verse_list == [1, 2, 3, 4, 3, 9, 10]

    def test_psalm_29_sub_part_plus_only(self):
        """'Psalms 29:3b+9b-10' — sub-part with + treated as comma."""
        r = parse_reference("Psalms 29:3b+9b-10")
        assert r is not None
        assert r.book_osis == "Ps"
        assert r.chapter == 29
        assert r.verse == 3
        assert r.end_verse == 10
        assert r.verse_list == [3, 9, 10]

    def test_psalm_29_plus_joins_noncontiguous(self):
        """'+' joins non-contiguous sub-verses: 'Psalms 29:1+4' → [1, 4]."""
        r = parse_reference("Psalms 29:1+4")
        assert r is not None
        assert r.book_osis == "Ps"
        assert r.chapter == 29
        assert r.verse == 1
        assert r.end_verse == 4
        assert r.verse_list == [1, 4]

    def test_psalm_sub_part_multiple_letters(self):
        """Sub-parts a-e all stripped: 'Psalms 103:1a+2b+3c+4d+5e' → [1,2,3,4,5]."""
        r = parse_reference("Psalms 103:1a+2b+3c+4d+5e")
        assert r is not None
        assert r.book_osis == "Ps"
        assert r.chapter == 103
        assert r.verse_list == [1, 2, 3, 4, 5]

    def test_matthew_3_13_17_range(self):
        """'Matthew 3:13-17' — simple continuous range (Baptism gospel)."""
        r = parse_reference("Matthew 3:13-17")
        assert r is not None
        assert r.book_osis == "Matt"
        assert r.chapter == 3
        assert r.verse == 13
        assert r.end_verse == 17
        assert r.verse_list is None

    def test_lectionary_baptism_of_lord_2026_01_11(self):
        """Baptism of the Lord 2026-01-11 lectionary lookup succeeds."""
        from accordance_parser.lectionary import get_lectionary_for_date_string

        result = get_lectionary_for_date_string("2026-01-11")
        assert result is not None
        season, readings = result
        assert "Baptism" in season
        # All four readings should parse
        for key in ("first", "psalm", "second", "gospel"):
            r = parse_reference(readings[key])
            assert r is not None, f"Reading '{key}' ({readings[key]}) failed to parse"

    def test_baptism_psalm_has_sub_parts(self):
        """Baptism Psalm reading contains sub-part notation."""
        from accordance_parser.lectionary import get_lectionary_for_date_string

        _, readings = get_lectionary_for_date_string("2026-01-11")
        psalm_ref = readings["psalm"]
        # The raw reference (before conversion) contains 'b' and '+'
        assert "b" in psalm_ref or "+" in psalm_ref, (
            f"Expected sub-part notation in psalm ref, got: {psalm_ref}"
        )


# =============================================================================
# Priest #4 — Corpus Christi Comma-Separated Ranges
# =============================================================================

class TestPriest4CorpusChristi:
    """Corpus Christi (2026-06-07): Deuteronomy 8, John 6, 1 Cor 10."""

    def test_deuteronomy_8_sub_part_comma_range(self):
        """'Deuteronomy 8:2-3, 14b-16a' — sub-parts in comma skip-range."""
        r = parse_reference("Deuteronomy 8:2-3, 14b-16a")
        assert r is not None
        assert r.book_osis == "Deut"
        assert r.chapter == 8
        assert r.verse == 2
        assert r.end_verse == 16
        # 14b → 14, 16a → 16; skip-range skips verses 4-13
        assert r.verse_list == [2, 3, 14, 15, 16]

    def test_deuteronomy_8_no_subpart_for_comparison(self):
        """'Deuteronomy 8:2-3, 14-16' — same ranges without sub-parts."""
        r = parse_reference("Deuteronomy 8:2-3, 14-16")
        assert r is not None
        assert r.book_osis == "Deut"
        assert r.chapter == 8
        assert r.verse_list == [2, 3, 14, 15, 16]

    def test_john_6_51_58_continuous_range(self):
        """'John 6:51-58' — continuous range (Bread of Life discourse)."""
        r = parse_reference("John 6:51-58")
        assert r is not None
        assert r.book_osis == "John"
        assert r.chapter == 6
        assert r.verse == 51
        assert r.end_verse == 58
        assert r.verse_list is None

    def test_1cor_10_16_17_range(self):
        """'1 Corinthians 10:16-17' — simple range (Eucharistic cup/bread)."""
        r = parse_reference("1 Corinthians 10:16-17")
        assert r is not None
        assert r.book_osis == "1Cor"
        assert r.chapter == 10
        assert r.verse == 16
        assert r.end_verse == 17
        assert r.verse_list is None

    def test_lectionary_corpus_christi_2026_06_07(self):
        """Corpus Christi 2026-06-07 lectionary lookup succeeds."""
        from accordance_parser.lectionary import get_lectionary_for_date_string

        result = get_lectionary_for_date_string("2026-06-07")
        assert result is not None
        season, readings = result
        assert "Corpus Christi" in season or "Body" in season

        # First reading has sub-parts and commas → verse_list present
        r1 = parse_reference(readings["first"])
        assert r1 is not None
        assert r1.verse_list is not None, (
            f"First reading '{readings['first']}' should produce a verse_list"
        )

        # Psalm should parse
        r2 = parse_reference(readings["psalm"])
        assert r2 is not None

    def test_corpus_christi_first_reading_skips_verses(self):
        """Corpus Christi first reading correctly skips interior verses."""
        from accordance_parser.lectionary import get_lectionary_for_date_string

        _, readings = get_lectionary_for_date_string("2026-06-07")
        r = parse_reference(readings["first"])
        assert r is not None
        # Should include 2-3 and 14-16 but NOT 4-13
        vl = r.verse_list
        assert 2 in vl
        assert 3 in vl
        assert 14 in vl
        assert 15 in vl
        assert 16 in vl
        assert 4 not in vl
        assert 10 not in vl
        assert 13 not in vl

    def test_edge_single_comma_verse(self):
        """Single verse after comma: 'Genesis 1:1, 3' → [1, 3]."""
        r = parse_reference("Genesis 1:1, 3")
        assert r is not None
        assert r.book_osis == "Gen"
        assert r.chapter == 1
        assert r.verse_list == [1, 3]


# =============================================================================
# Priest #11 — Assumption Semicolon + Comma References
# =============================================================================

class TestPriest11Assumption:
    """Assumption (2026-08-15): Revelation 11:19a; 12:1-6a, 10ab."""

    def test_revelation_semicolon_with_subparts(self):
        """'Revelation 11:19a; 12:1-6a, 10ab' — semicolon, chapters differ."""
        r = parse_reference("Revelation 11:19a; 12:1-6a, 10ab")
        assert r is not None
        # Chapters differ (11 vs 12) → returns first segment only
        assert r.book_osis == "Rev"
        assert r.chapter == 11
        assert r.verse == 19
        assert r.end_verse is None
        assert r.verse_list is None

    def test_revelation_first_segment_parsed(self):
        """First segment of Assumption ref resolves to Rev 11:19."""
        r = parse_reference("Revelation 11:19a")
        assert r is not None
        assert r.book_osis == "Rev"
        assert r.chapter == 11
        assert r.verse == 19
        # Sub-part 'a' stripped → verse_list is None (single verse, no comma)

    def test_revelation_second_segment_with_comma(self):
        """'Revelation 12:1-6a, 10ab' — comma with sub-parts, chapter 12."""
        r = parse_reference("Revelation 12:1-6a, 10ab")
        assert r is not None
        assert r.book_osis == "Rev"
        assert r.chapter == 12
        # 1-6 (6a→6); 10ab now correctly stripped to 10
        assert r.verse_list == [1, 2, 3, 4, 5, 6, 10]

    def test_revelation_multi_letter_subpart_resolved(self):
        """Confirm multi-letter sub-part limitation is resolved.

        Before the regex fix, '10ab' was not stripped because \\b failed
        between consecutive word characters 'a' and 'b'. The updated regex
        r\"(\d+)[a-e]+\\b\" now handles multi-letter suffixes.
        """
        r = parse_reference("Revelation 12:1-6a, 10ab")
        assert r is not None
        assert r.book_osis == "Rev"
        assert r.chapter == 12
        # 10ab → 10 after sub-part stripping
        assert 10 in r.verse_list
        assert r.verse_list == [1, 2, 3, 4, 5, 6, 10]

    def test_luke_1_39_56_magnificat_range(self):
        """'Luke 1:39-56' — Magnificat pericope (continuous range)."""
        r = parse_reference("Luke 1:39-56")
        assert r is not None
        assert r.book_osis == "Luke"
        assert r.chapter == 1
        assert r.verse == 39
        assert r.end_verse == 56
        assert r.verse_list is None

    def test_lectionary_assumption_2026_08_15(self):
        """Assumption 2026-08-15 lectionary lookup succeeds."""
        from accordance_parser.lectionary import get_lectionary_for_date_string

        result = get_lectionary_for_date_string("2026-08-15")
        assert result is not None
        season, readings = result
        assert "Assumption" in season

        # All readings parse (first returns first seg only for semicolons)
        for key in ("first", "psalm", "second", "gospel"):
            r = parse_reference(readings[key])
            assert r is not None, f"Reading '{key}' ({readings[key]}) failed to parse"

    def test_semicolon_same_chapter_merge(self):
        """Semicolons in same chapter merge: 'Matt 5:3; 5:7-9' → [3,7,8,9]."""
        r = parse_reference("Matt 5:3; 5:7-9")
        assert r is not None
        assert r.book_osis == "Matt"
        assert r.chapter == 5
        assert r.verse_list == [3, 7, 8, 9]


# =============================================================================
# Theologian #3 — Comma-Separated Ranges in 1 Peter
# =============================================================================

class TestTheologian3FirstPeter:
    """Comma skip-range in 1 Peter 1:13-16, 22-23."""

    def test_1peter_comma_skip_range(self):
        """'1 Peter 1:13-16, 22-23' — NT epistle comma skip-range."""
        r = parse_reference("1 Peter 1:13-16, 22-23")
        assert r is not None
        assert r.book_osis == "1Pet"
        assert r.chapter == 1
        assert r.verse == 13
        assert r.end_verse == 23
        assert r.verse_list == [13, 14, 15, 16, 22, 23]

    def test_1peter_verse_list_contains_all_six(self):
        """Verse list contains all 6 expected verses."""
        r = parse_reference("1 Peter 1:13-16, 22-23")
        assert r is not None
        vl = r.verse_list
        for v in (13, 14, 15, 16, 22, 23):
            assert v in vl, f"Verse {v} missing from verse_list {vl}"

    def test_1peter_verse_list_skips_interior(self):
        """Verse list skips verses 17-21 (the interior gap)."""
        r = parse_reference("1 Peter 1:13-16, 22-23")
        assert r is not None
        vl = r.verse_list
        for v in (17, 18, 19, 20, 21):
            assert v not in vl, f"Verse {v} should NOT be in verse_list {vl}"

    def test_1peter_verse_list_correct_length(self):
        """Verse list has exactly 6 verses."""
        r = parse_reference("1 Peter 1:13-16, 22-23")
        assert r is not None
        assert len(r.verse_list) == 6

    def test_1peter_individual_verses(self):
        """Individual verses in the range all parse correctly."""
        for v in (13, 14, 15, 16, 22, 23):
            ref = f"1 Peter 1:{v}"
            r = parse_reference(ref)
            assert r is not None, f"Failed to parse '{ref}'"
            assert r.book_osis == "1Pet"
            assert r.chapter == 1
            assert r.verse == v

    def test_1peter_full_range_with_abbreviation(self):
        """'1Pet 1:13-16, 22-23' — abbreviated book name."""
        r = parse_reference("1Pet 1:13-16, 22-23")
        assert r is not None
        assert r.book_osis == "1Pet"
        assert r.verse_list == [13, 14, 15, 16, 22, 23]


# =============================================================================
# Theologian #12 — Baptism of the Lord Ranges
# =============================================================================

class TestTheologian12BaptismRanges:
    """Baptism of the Lord: Isaiah 42:1-4, 6-7 skipping verse 5."""

    def test_isaiah_42_skip_range(self):
        """'Isaiah 42:1-4, 6-7' — comma skip-range, skipping verse 5."""
        r = parse_reference("Isaiah 42:1-4, 6-7")
        assert r is not None
        assert r.book_osis == "Isa"
        assert r.chapter == 42
        assert r.verse == 1
        assert r.end_verse == 7
        assert r.verse_list == [1, 2, 3, 4, 6, 7]

    def test_isaiah_42_skips_verse_5(self):
        """Verse 5 is NOT in the verse_list (the gap between ranges)."""
        r = parse_reference("Isaiah 42:1-4, 6-7")
        assert r is not None
        assert 5 not in r.verse_list

    def test_isaiah_42_contains_all_expected(self):
        """Verses 1,2,3,4,6,7 are all present."""
        r = parse_reference("Isaiah 42:1-4, 6-7")
        assert r is not None
        for v in (1, 2, 3, 4, 6, 7):
            assert v in r.verse_list, f"Verse {v} missing from {r.verse_list}"

    def test_baptism_lectionary_isaiah_parses(self):
        """Baptism of the Lord first reading parses with verse_list."""
        from accordance_parser.lectionary import get_lectionary_for_date_string

        _, readings = get_lectionary_for_date_string("2026-01-11")
        r = parse_reference(readings["first"])
        assert r is not None
        assert r.book_osis == "Isa"
        assert r.verse_list == [1, 2, 3, 4, 6, 7]

    def test_baptism_lectionary_all_have_correct_book_osis(self):
        """All Baptism readings resolve to the correct OSIS book codes."""
        from accordance_parser.lectionary import get_lectionary_for_date_string

        _, readings = get_lectionary_for_date_string("2026-01-11")
        expected_osis = {
            "first": "Isa",
            "psalm": "Ps",
            "second": "Acts",
            "gospel": "Matt",
        }
        for key, expected in expected_osis.items():
            r = parse_reference(readings[key])
            assert r is not None, f"Reading '{key}' failed to parse"
            assert r.book_osis == expected, (
                f"Reading '{key}': expected {expected}, got {r.book_osis}"
            )
