"""
Tests for advanced reference parsing features in parse_reference().

Covers:
  1. Psalm verse sub-part notation ("+" and "a/b/c/d/e" suffixes)
  2. Semicolon references ("Acts 22:30; 23:6-11")
  3. Edge cases and backward compatibility
"""

from accordance_parser.canon import (
    parse_reference,
)


# =============================================================================
# 1. Psalm verse sub-part notation (US lectionary)
# =============================================================================

def test_psalm_plus_as_comma():
    """'+' treated as comma: 'Psalms 67:2-3, 5, 6+8' → verses [2,3,5,6,8]"""
    r = parse_reference("Psalms 67:2-3, 5, 6+8")
    assert r is not None
    assert r.book_osis == "Ps"
    assert r.chapter == 67
    assert r.verse == 2
    assert r.end_verse == 8
    assert r.verse_list == [2, 3, 5, 6, 8]


def test_psalm_sub_part_b():
    """'11b' stripped to 11: 'Psalms 16:5, 8, 9-10, 11b' → verses [5,8,9,10,11]"""
    r = parse_reference("Psalms 16:5, 8, 9-10, 11b")
    assert r is not None
    assert r.book_osis == "Ps"
    assert r.chapter == 16
    assert r.verse == 5
    assert r.end_verse == 11
    assert r.verse_list == [5, 8, 9, 10, 11]


def test_psalm_plus_and_sub_part():
    """'+' and 'b' combined: 'Psalms 29:1-2, 3b+9b-10' → verses [1,2,3,9,10]"""
    r = parse_reference("Psalms 29:1-2, 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
    assert r.verse_list == [1, 2, 3, 9, 10]


def test_psalm_multiple_sub_parts():
    """Multiple '+' and 'b': 'Psalms 103:1-2, 3-4b+8b+10b' → verses [1,2,3,4,8,10]"""
    r = parse_reference("Psalms 103:1-2, 3-4b+8b+10b")
    assert r is not None
    assert r.book_osis == "Ps"
    assert r.chapter == 103
    assert r.verse == 1
    assert r.end_verse == 10
    assert r.verse_list == [1, 2, 3, 4, 8, 10]


def test_sub_part_a():
    """Sub-part 'a' is also stripped: verse '5a' → 5"""
    r = parse_reference("Psalms 100:1-2, 5a")
    assert r is not None
    assert r.book_osis == "Ps"
    assert r.chapter == 100
    assert r.verse == 1
    assert r.end_verse == 5
    assert r.verse_list == [1, 2, 5]


def test_sub_part_c():
    """Sub-part 'c' is also stripped: verse '8c' → 8"""
    r = parse_reference("Psalms 100:1 , 8c")
    assert r is not None
    assert r.book_osis == "Ps"
    assert r.chapter == 100
    assert r.verse == 1
    assert r.end_verse == 8
    assert r.verse_list == [1, 8]


def test_sub_part_d():
    """Sub-part 'd' is also stripped: verse '3d' → 3"""
    r = parse_reference("Psalms 100:3d")
    assert r is not None
    assert r.book_osis == "Ps"
    assert r.chapter == 100
    assert r.verse == 3
    assert r.end_verse is None


def test_sub_part_e():
    """Sub-part 'e' is also stripped: verse '7e' → 7"""
    r = parse_reference("Psalms 100:7e")
    assert r is not None
    assert r.book_osis == "Ps"
    assert r.chapter == 100
    assert r.verse == 7
    assert r.end_verse is None


def test_plus_only_no_comma():
    """'+' works without commas: 'Psalms 67:6+8' → verses [6, 8]"""
    r = parse_reference("Psalms 67:6+8")
    assert r is not None
    assert r.book_osis == "Ps"
    assert r.chapter == 67
    assert r.verse == 6
    assert r.end_verse == 8
    assert r.verse_list == [6, 8]


def test_sub_part_on_range():
    """Sub-part on a range end: 'Psalms 103:3-4b' → verses [3,4]"""
    r = parse_reference("Psalms 103:3-4b")
    assert r is not None
    assert r.book_osis == "Ps"
    assert r.chapter == 103
    assert r.verse == 3
    assert r.end_verse == 4
    # Not a comma ref, so verse_list is None
    assert r.verse_list is None


def test_sub_part_no_comma():
    """Sub-part without comma: 'Psalms 16:11b' → verse 11"""
    r = parse_reference("Psalms 16:11b")
    assert r is not None
    assert r.book_osis == "Ps"
    assert r.chapter == 16
    assert r.verse == 11
    assert r.end_verse is None
    assert r.verse_list is None


# =============================================================================
# 2. Semicolon references
# =============================================================================

def test_semicolon_different_chapters():
    """'Acts 22:30; 23:6-11' — chapters differ → return first segment only"""
    r = parse_reference("Acts 22:30; 23:6-11")
    assert r is not None
    assert r.book_osis == "Acts"
    assert r.chapter == 22
    assert r.verse == 30
    assert r.end_verse is None
    assert r.verse_list is None


def test_semicolon_same_chapter_merge():
    """'Matt 5:3; 5:7-9' — same chapter → merge verses [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 == 3
    assert r.end_verse == 9
    assert r.verse_list == [3, 7, 8, 9]


def test_semicolon_multi_segment_same_chapter():
    """'Matt 5:3; 5:7-9; 5:12' → merge all three segments"""
    r = parse_reference("Matt 5:3; 5:7-9; 5:12")
    assert r is not None
    assert r.book_osis == "Matt"
    assert r.chapter == 5
    assert r.verse == 3
    assert r.end_verse == 12
    assert r.verse_list == [3, 7, 8, 9, 12]


def test_semicolon_overlapping_verses():
    """Overlapping ranges in semicolon segments → deduplicated"""
    r = parse_reference("Matt 5:3-6; 5:5-7")
    assert r is not None
    assert r.book_osis == "Matt"
    assert r.chapter == 5
    assert r.verse == 3
    assert r.end_verse == 7
    assert r.verse_list == [3, 4, 5, 6, 7]  # 5,6 deduplicated


def test_semicolon_same_chapter_range_first():
    """First semicolon segment is a range"""
    r = parse_reference("John 3:16-18; 3:20-21")
    assert r is not None
    assert r.book_osis == "John"
    assert r.chapter == 3
    assert r.verse == 16
    assert r.end_verse == 21
    assert r.verse_list == [16, 17, 18, 20, 21]


def test_semicolon_edge_cases():
    """Edge cases for semicolon references."""
    # No first segment
    assert parse_reference("; 23:6-11") is None
    # Second segment syntactically invalid → return first segment
    r = parse_reference("Acts 22:30; notachapter:1")
    assert r is not None
    assert r.book_osis == "Acts"
    assert r.chapter == 22
    assert r.verse == 30
    # Unknown book in first segment
    assert parse_reference("nonexistentbook 1:1; 2:3") is None


# =============================================================================
# 3. Combined edge cases
# =============================================================================

def test_sub_part_on_semicolon():
    """Sub-part stripping + semicolon: 'Psalms 16:11b; 16:12'"""
    r = parse_reference("Psalms 16:11b; 16:12")
    assert r is not None
    assert r.book_osis == "Ps"
    assert r.chapter == 16
    assert r.verse == 11
    assert r.end_verse == 12
    assert r.verse_list == [11, 12]


def test_backward_compat_simple():
    """Simple refs still work after preprocessing changes"""
    r = parse_reference("Genesis 1:1")
    assert r is not None
    assert r.book_osis == "Gen"
    assert r.chapter == 1
    assert r.verse == 1
    assert r.end_verse is None


def test_backward_compat_range():
    """Range refs still work"""
    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


def test_backward_compat_comma():
    """Comma refs still work (no '+' / sub-parts)"""
    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_psalm_normal_comma_ref():
    """Normal Psalm comma ref without special notation still works"""
    r = parse_reference("Psalms 68:10-11, 20-21")
    assert r is not None
    assert r.book_osis == "Ps"
    assert r.chapter == 68
    assert r.verse == 10
    assert r.end_verse == 21
    assert r.verse_list == [10, 11, 20, 21]


# =============================================================================
# 4. Multi-letter sub-part stripping
# =============================================================================

def test_sub_part_multi_letter_ab():
    """Multi-letter sub-part 'ab' stripped: 'Psalms 29:10ab-20' → verses 10-20"""
    r = parse_reference("Psalms 29:10ab-20")
    assert r is not None
    assert r.book_osis == "Ps"
    assert r.chapter == 29
    assert r.verse == 10
    assert r.end_verse == 20
    assert r.verse_list is None  # not a comma ref


def test_sub_part_multi_letter_ef():
    """Multi-letter sub-part 'ef' stripped: 'Isaiah 42:6ef' → 'Isaiah 42:6'"""
    r = parse_reference("Isaiah 42:6ef")
    assert r is not None
    assert r.book_osis == "Isa"
    assert r.chapter == 42
    assert r.verse == 6
    assert r.end_verse is None


def test_sub_part_multi_letter_in_comma_range():
    """Multi-letter '10ab' stripped in comma range: 'Rev 12:1-6a, 10ab' → [1,2,3,4,5,6,10]"""
    r = parse_reference("Revelation 12:1-6a, 10ab")
    assert r is not None
    assert r.book_osis == "Rev"
    assert r.chapter == 12
    assert r.verse == 1
    assert r.end_verse == 10
    assert r.verse_list == [1, 2, 3, 4, 5, 6, 10]


def test_sub_part_single_letter_still_works():
    """Single-letter sub-part '3b' still strips: 'Psalms 29:3b-5' → verses 3-5"""
    r = parse_reference("Psalms 29:3b-5")
    assert r is not None
    assert r.book_osis == "Ps"
    assert r.chapter == 29
    assert r.verse == 3
    assert r.end_verse == 5
    assert r.verse_list is None


def test_sub_part_no_letters_unchanged():
    """No sub-part: 'Psalms 29:3-5' unchanged"""
    r = parse_reference("Psalms 29:3-5")
    assert r is not None
    assert r.book_osis == "Ps"
    assert r.chapter == 29
    assert r.verse == 3
    assert r.end_verse == 5
    assert r.verse_list is None
