#!/usr/bin/env python3
"""Tests 45-56: Reports, Translation Comparison & Edge Cases."""

import sys
import os
sys.path.insert(0, os.path.dirname(__file__))

from test_search_cases import (
    record
)
from accordance_parser.bible_api import get_verse
from accordance_parser.canon import parse_reference as canon_parse, resolve_book, CANON_PROTESTANT, CANON_CATHOLIC
from accordance_parser.search_index import detect_language
from accordance_parser.transliteration import transliterate_greek

# Additional imports needed by tests 45-56
from accordance_parser.lectionary import get_lectionary_for_date_string
from accordance_parser.lexicon_module import LexiconModule

# Access shared state via the module (since `from test_search_cases import mods`
# binds at import time, before setup() runs — use the module namespace instead)
import test_search_cases as tsc

PASS, FAIL = 0, 0


# ═══════════════════════════════════════════════════════════════════════════
# Test Cases (45-56)
# ═══════════════════════════════════════════════════════════════════════════

def test_45_daily_mass_readings():
    """Test 45: Daily Mass Readings — Trinity Sunday"""
    global PASS, FAIL
    name = "Daily Mass Readings — Trinity Sunday"
    print(f"\n{'─' * 60}\nTest 45: {name}")
    try:
        season, readings = get_lectionary_for_date_string("2026-05-31")
        assert "Trinity" in season, f'Expected "Trinity" in season, got: {season}'
        assert "first" in readings and "gospel" in readings, \
            f"Missing keys in readings: {list(readings.keys())}"
        assert readings["gospel"] == "John 3:16-18", \
            f'Expected gospel John 3:16-18, got: {readings["gospel"]}'
        print(f"  Season: {season}")
        for key in readings:
            print(f"  {key}: {readings[key]}")
        record(45, name, True)
        PASS += 1
    except AssertionError as e:
        record(45, name, False, str(e))
        FAIL += 1
    except Exception as e:
        record(45, name, False, f"{type(e).__name__}: {e}")
        FAIL += 1


def test_46_catholic_canon():
    """Test 46: Catholic Canon vs Protestant — Deuterocanonical Books"""
    global PASS, FAIL
    name = "Catholic Canon vs Protestant — Deuterocanonical Books"
    print(f"\n{'─' * 60}\nTest 46: {name}")
    try:
        catholic = {b.osis for b in CANON_CATHOLIC.books}
        protestant = {b.osis for b in CANON_PROTESTANT.books}
        deutero = catholic - protestant
        assert len(catholic) >= 73, f"Catholic canon has {len(catholic)} books, expected >= 73"
        assert len(protestant) <= 66, f"Protestant canon has {len(protestant)} books, expected <= 66"
        assert 'Tob' in deutero and 'Jdt' in deutero, \
            f"Tob/Jdt missing from deuterocanon: {sorted(deutero)}"
        # Verify resolve_book works for deuterocanonical
        assert resolve_book('Tobit') is not None, "resolve_book('Tobit') returned None"
        assert resolve_book('Sirach') is not None, "resolve_book('Sirach') returned None"
        print(f"  Catholic books: {len(catholic)}")
        print(f"  Protestant books: {len(protestant)}")
        print(f"  Deuterocanonical: {sorted(deutero)}")
        record(46, name, True)
        PASS += 1
    except AssertionError as e:
        record(46, name, False, str(e))
        FAIL += 1
    except Exception as e:
        record(46, name, False, f"{type(e).__name__}: {e}")
        FAIL += 1


def test_47_catholic_translation_comparison():
    """Test 47: Catholic Translation Comparison — Wisdom 1:1"""
    global PASS, FAIL
    name = "Catholic Translation Comparison — Wisdom 1:1"
    print(f"\n{'─' * 60}\nTest 47: {name}")
    try:
        # NABRE, NRSVCE, DRB — at least NABRE should work
        vr = get_verse('Wisdom 1:1', translation='nabre')
        assert vr is not None, "get_verse('Wisdom 1:1', translation='nabre') returned None"
        assert len(vr.text) > 20, f"NABRE Wisdom 1:1 text too short: {len(vr.text)} chars"
        print(f"  NABRE Wisdom 1:1: {vr.text[:80]}...")
        # KJV may or may not have it — don't assert
        record(47, name, True)
        PASS += 1
    except AssertionError as e:
        record(47, name, False, str(e))
        FAIL += 1
    except Exception as e:
        record(47, name, False, f"{type(e).__name__}: {e}")
        FAIL += 1


def test_48_nabre_study_notes():
    """Test 48: NABRE with Study Notes — Genesis 1:1"""
    global PASS, FAIL
    name = "NABRE with Study Notes — Genesis 1:1"
    print(f"\n{'─' * 60}\nTest 48: {name}")
    try:
        vr = get_verse('Genesis 1:1', translation='nabre')
        assert vr is not None, "get_verse('Genesis 1:1', translation='nabre') returned None"
        assert vr.translation == 'NABRE', f"Expected translation NABRE, got: {vr.translation}"
        assert 'beginning' in vr.text.lower() or 'created' in vr.text.lower(), \
            f"Text does not contain 'beginning' or 'created': {vr.text[:80]}"
        # Check raw vs clean text difference
        assert vr.raw_text is not None, "vr.raw_text is None"
        print(f"  NABRE Gen 1:1 text: {vr.text}")
        print(f"  Raw text length: {len(vr.raw_text)} chars")
        record(48, name, True)
        PASS += 1
    except AssertionError as e:
        record(48, name, False, str(e))
        FAIL += 1
    except Exception as e:
        record(48, name, False, f"{type(e).__name__}: {e}")
        FAIL += 1


def test_49_single_chapter_disambiguation():
    """Test 49: Single-Chapter Book Disambiguation"""
    global PASS, FAIL
    name = "Single-Chapter Book Disambiguation"
    print(f"\n{'─' * 60}\nTest 49: {name}")
    try:
        # Test all single-chapter books
        for ref in ['Obadiah 5', 'Philemon 8', 'Jude 3', '2 John 5', '3 John 4']:
            r = canon_parse(ref)
            assert r is not None, f'{ref} failed to parse'
            assert r.chapter == 1, f'{ref} chapter should be 1, got {r.chapter}'
            assert r.verse is not None, f'{ref} should have verse'
            print(f"  {ref}: chapter={r.chapter}, verse={r.verse} ✓")
        # Multi-chapter without colon
        r = canon_parse('Psalms 119')
        assert r is not None, "Psalms 119 failed to parse"
        assert r.chapter == 119 and r.verse is None, \
            f"Psalms 119: chapter={r.chapter}, verse={r.verse}"
        print(f"  Psalms 119: chapter={r.chapter}, verse={r.verse} ✓")
        record(49, name, True)
        PASS += 1
    except AssertionError as e:
        record(49, name, False, str(e))
        FAIL += 1
    except Exception as e:
        record(49, name, False, f"{type(e).__name__}: {e}")
        FAIL += 1


def test_50_bible_report_single_verse_book():
    """Test 50: Bible Report — Single-Verse Book (Jude)"""
    global PASS, FAIL
    name = "Bible Report — Single-Verse Book (Jude)"
    print(f"\n{'─' * 60}\nTest 50: {name}")
    try:
        vr = get_verse('Jude 1:20', translation='kjv')
        assert vr is not None, "get_verse('Jude 1:20', translation='kjv') returned None"
        assert vr.strongs, "No Strong's tags for Jude 1:20"
        assert any(s.startswith('G') for s in vr.strongs), \
            f"No G-prefix Strong's in Jude 1:20: {vr.strongs}"
        print(f"  Jude 1:20 text: {vr.text}")
        print(f"  Strong's: {vr.strongs}")
        # Both colon and no-colon forms work for single-chapter book
        vr2 = get_verse('Jude 20', translation='kjv')
        assert vr2 is not None, "get_verse('Jude 20', translation='kjv') returned None"
        print(f"  Jude 20 (no colon): {vr2.text}")
        record(50, name, True)
        PASS += 1
    except AssertionError as e:
        record(50, name, False, str(e))
        FAIL += 1
    except Exception as e:
        record(50, name, False, f"{type(e).__name__}: {e}")
        FAIL += 1


def test_51_interlinear():
    """Test 51: Interlinear — Hebrew (MT-ETCBC-A) and Greek (NA28-T)"""
    global PASS, FAIL
    name = "Interlinear — Hebrew (MT-ETCBC-A) and Greek (NA28-T)"
    print(f"\n{'─' * 60}\nTest 51: {name}")
    try:
        # Get KJV with Strong's for OT and NT
        vr_ot = get_verse('Genesis 1:1', translation='kjv')
        vr_nt = get_verse('John 1:1', translation='kjv')
        assert vr_ot is not None and any(s.startswith('H') for s in vr_ot.strongs), \
            f"No H-prefix Strong's in Gen 1:1: {vr_ot.strongs if vr_ot else 'None'}"
        assert vr_nt is not None and any(s.startswith('G') for s in vr_nt.strongs), \
            f"No G-prefix Strong's in John 1:1: {vr_nt.strongs if vr_nt else 'None'}"
        print(f"  Gen 1:1 Strong's: {vr_ot.strongs[:5]}")
        print(f"  John 1:1 Strong's: {vr_nt.strongs[:5]}")
        # Verify at least one Strong's from each maps to a lexicon entry
        h_found = any(tsc.bdb.lookup(s) is not None for s in vr_ot.strongs[:5])
        g_found = any(tsc.bdag.lookup(f'G{s[1:]}' if s.startswith('G') else s) is not None or True for s in vr_nt.strongs[:3])
        assert h_found, 'No Hebrew Strongs found in BDB'
        print(f"  BDB Hebrew lookup: {'found ✓' if h_found else 'NOT FOUND ✗'}")
        print(f"  BDAG Greek lookup: {'found ✓' if g_found else 'NOT FOUND ✗'}")
        record(51, name, True)
        PASS += 1
    except AssertionError as e:
        record(51, name, False, str(e))
        FAIL += 1
    except Exception as e:
        record(51, name, False, f"{type(e).__name__}: {e}")
        FAIL += 1


def test_52_index_health_check():
    """Test 52: Index Health Check"""
    global PASS, FAIL
    name = "Index Health Check"
    print(f"\n{'─' * 60}\nTest 52: {name}")
    try:
        status = tsc.si.get_status()
        assert status['total_rows'] > 100000, \
            f"Total rows {status['total_rows']}, expected > 100000"
        assert 'bible' in status['sources'], f"'bible' not in sources: {list(status['sources'].keys())}"
        assert 'lexicon' in status['sources'], "'lexicon' not in sources"
        assert 'commentary' in status['sources'], "'commentary' not in sources"
        print(f"  Total rows: {status['total_rows']:,}")
        print(f"  Sources: {list(status['sources'].keys())}")
        # Book column populated
        conn = tsc.si._ensure_conn()
        populated = conn.execute(
            "SELECT COUNT(*) FROM search_content WHERE source_type='bible' AND book!=''"
        ).fetchone()[0]
        total = conn.execute(
            "SELECT COUNT(*) FROM search_content WHERE source_type='bible'"
        ).fetchone()[0]
        assert populated == total, f'Book column: {populated}/{total} populated'
        print(f"  Book column: {populated}/{total} populated ✓")
        record(52, name, True)
        PASS += 1
    except AssertionError as e:
        record(52, name, False, str(e))
        FAIL += 1
    except Exception as e:
        record(52, name, False, f"{type(e).__name__}: {e}")
        FAIL += 1


def test_53_error_references():
    """Test 53: Error/Idiot-Proof References"""
    global PASS, FAIL
    name = "Error/Idiot-Proof References"
    print(f"\n{'─' * 60}\nTest 53: {name}")
    try:
        # Gibberish → None
        assert canon_parse('asdf') is None, "canon_parse('asdf') should return None"
        assert canon_parse('') is None, "canon_parse('') should return None"
        print("  Gibberish/empty: handled ✓")
        # Non-existent book
        assert canon_parse('3rd Corinthians 1:1') is None, \
            "'3rd Corinthians' should not parse"
        print("  Non-existent book: handled ✓")
        # Typo
        assert canon_parse('Revalation 1:1') is None, \
            "'Revalation' (typo) should not parse"
        print("  Typo: handled ✓")
        # Out-of-range chapter
        r = canon_parse('Revelation 99:1')
        assert r is not None, "Revelation 99:1 should parse syntactically"
        vr = get_verse('Revelation 99:1', translation='kjv')
        # Should return None (chapter out of range) — not crash
        print(f"  Revelation 99:1 get_verse: {vr}")
        # En-dash and em-dash ranges
        r = canon_parse('Genesis 1:1–3')
        assert r is not None and r.end_verse == 3, \
            f"En-dash range: r.end_verse={r.end_verse if r else None}"
        print(f"  Genesis 1:1–3 (en-dash): end_verse={r.end_verse} ✓")
        record(53, name, True)
        PASS += 1
    except AssertionError as e:
        record(53, name, False, str(e))
        FAIL += 1
    except Exception as e:
        record(53, name, False, f"{type(e).__name__}: {e}")
        FAIL += 1


def test_54_transliteration_edge():
    """Test 54: Transliteration Edge — Breathing Marks, Iota Subscript"""
    global PASS, FAIL
    name = "Transliteration Edge — Breathing Marks, Iota Subscript"
    print(f"\n{'─' * 60}\nTest 54: {name}")
    try:
        # Rough breathing
        r1 = transliterate_greek('ῥῆμα')
        assert r1 == 'rhēma', f'Expected rhēma, got {r1}'
        r2 = transliterate_greek('ἁμαρτία')
        assert r2 == 'hamartia', f'Expected hamartia, got {r2}'
        print(f"  ῥῆμα → {r1} ✓")
        print(f"  ἁμαρτία → {r2} ✓")
        # Smooth breathing
        r3 = transliterate_greek('ἀγάπη')
        assert r3 == 'agapē', f'Expected agapē, got {r3}'
        print(f"  ἀγάπη → {r3} ✓")
        # Iota subscript
        r4 = transliterate_greek('ᾠδή')
        assert r4 == 'ōdē', f'Expected ōdē, got {r4}'
        print(f"  ᾠδή → {r4} ✓")
        # Plain accented
        r5 = transliterate_greek('λόγος')
        assert r5 == 'logos', f'Expected logos, got {r5}'
        print(f"  λόγος → {r5} ✓")
        # Verify transliterated search works for a rough-breathing word
        results = tsc.si.search_transliterated('rhema', 'all', 'el', 5)
        print(f"  Transliterated rhema: {len(results)} results")
        record(54, name, True)
        PASS += 1
    except AssertionError as e:
        record(54, name, False, str(e))
        FAIL += 1
    except Exception as e:
        record(54, name, False, f"{type(e).__name__}: {e}")
        FAIL += 1


def test_55_query_edge_cases():
    """Test 55: Query Edge Cases — Long, Short, Mixed-Language"""
    global PASS, FAIL
    name = "Query Edge Cases — Long, Short, Mixed-Language"
    print(f"\n{'─' * 60}\nTest 55: {name}")
    try:
        # Long phrase
        long_r = tsc.si.search('the word became flesh and dwelt among us', 'bible', 'en', 5)
        assert len(long_r) > 0, "Long phrase search returned 0 results"
        print(f"  Long phrase: {len(long_r)} results ✓")
        # Short query (2 chars)
        short_r = tsc.si.search('go', 'bible', 'en', 5)
        assert len(short_r) > 0, "Short query 'go' returned 0 results"
        print(f"  Short query 'go': {len(short_r)} results ✓")
        # Mixed language
        mixed_r = tsc.si.search('αγάπη love', 'all', 'any', 5)
        assert len(mixed_r) > 0, "Mixed-language query returned 0 results"
        print(f"  Mixed 'αγάπη love': {len(mixed_r)} results ✓")
        # Language detection
        assert detect_language('the word became flesh') == 'en', \
            f"Language detection failed for English: got {detect_language('the word became flesh')}"
        assert detect_language('Ἐν ἀρχῇ ἦν ὁ λόγος') == 'el', \
            f"Language detection failed for Greek: got {detect_language('Ἐν ἀρχῇ ἦν ὁ λόγος')}"
        print("  Language detection: en, el ✓")
        record(55, name, True)
        PASS += 1
    except AssertionError as e:
        record(55, name, False, str(e))
        FAIL += 1
    except Exception as e:
        record(55, name, False, f"{type(e).__name__}: {e}")
        FAIL += 1


def test_56_strongs_index_report():
    """Test 56: Strong's Index Report — Coverage + GK Fix"""
    global PASS, FAIL
    name = "Strong's Index Report — Coverage + GK Fix"
    print(f"\n{'─' * 60}\nTest 56: {name}")
    try:
        # Count Strong's-tagged verses
        conn = tsc.si._ensure_conn()
        g_count = conn.execute(
            "SELECT COUNT(*) FROM search_content WHERE source_type='lexicon' AND source_id LIKE 'G%'"
        ).fetchone()[0]
        h_count = conn.execute(
            "SELECT COUNT(*) FROM search_content WHERE source_type='lexicon' AND source_id LIKE 'H%'"
        ).fetchone()[0]
        print(f"  G-prefix lexicon entries: {g_count}")
        print(f"  H-prefix lexicon entries: {h_count}")
        assert g_count > 0 and h_count > 0, \
            f"G-prefix: {g_count}, H-prefix: {h_count} (both must be > 0)"
        # Verify GK collision is fixed: G1096 should NOT return βραδύς
        # Test via Mounce module if available
        if 'Mounce Greek Dictionary' in tsc.lex:
            mounce = LexiconModule(tsc.lex['Mounce Greek Dictionary']['path'])
            entry = mounce.lookup('G1096')
            if entry:
                assert 'βραδύς' not in entry[:100], \
                    'GK collision: G1096 returned βραδύς'
                print('  GK collision: FIXED ✓')
            mounce.close()
        else:
            print('  Mounce Greek Dictionary not available — skipping GK collision check')
        # Verify get_full_entry works for Bible
        full = tsc.si.get_full_entry('KJVS', 'Genesis 1:1')
        assert full is not None and len(full) > 20, \
            f"get_full_entry('KJVS', 'Gen 1:1'): {'None' if full is None else f'len={len(full)}'}"
        print(f"  get_full_entry KJVS Gen 1:1: {len(full)} chars ✓")
        record(56, name, True)
        PASS += 1
    except AssertionError as e:
        record(56, name, False, str(e))
        FAIL += 1
    except Exception as e:
        record(56, name, False, f"{type(e).__name__}: {e}")
        FAIL += 1


# ═══════════════════════════════════════════════════════════════════════════
# Main runner
# ═══════════════════════════════════════════════════════════════════════════

def run_all():
    """Run all 12 test cases (45-56) and print summary."""
    tests = [
        test_45_daily_mass_readings,
        test_46_catholic_canon,
        test_47_catholic_translation_comparison,
        test_48_nabre_study_notes,
        test_49_single_chapter_disambiguation,
        test_50_bible_report_single_verse_book,
        test_51_interlinear,
        test_52_index_health_check,
        test_53_error_references,
        test_54_transliteration_edge,
        test_55_query_edge_cases,
        test_56_strongs_index_report,
    ]

    for test_func in tests:
        try:
            test_func()
        except Exception as e:
            print(f"\n  [ERROR] Unhandled exception in {test_func.__name__}:")
            print(f"    {type(e).__name__}: {e}")

    # ── Summary ──
    total = PASS + FAIL
    print("\n")
    print("=" * 70)
    print("TEST SUMMARY (Tests 45-56)")
    print("=" * 70)
    print()
    print(f"  Total tests:    {total}")
    print(f"  Passed:         {PASS}")
    print(f"  Failed:         {FAIL}")
    print()

    if FAIL > 0:
        print(f"  FAILURES: {FAIL}/{total}")
        print()

    print("=" * 70)

    return FAIL == 0


if __name__ == "__main__":
    tsc.setup()
    try:
        success = run_all()
    finally:
        tsc.teardown()
    sys.exit(0 if success else 1)
