"""
Bible-Companion: Christological Conversational AI Service
Interprets Scripture through Christ's incarnation, atonement, and resurrection.

Domain: ai-bible.pikzulstudios.com/api/chat
Model: LFM2.5 (1.2B parameters)
Local Inference: http://192.168.1.169:1234/v1
VPS Inference: http://localhost:11434 (ollama)
"""

import asyncio
import json
import os
import re
import sqlite3
import logging
from functools import lru_cache
from datetime import datetime
from pathlib import Path
from typing import Optional, Dict, Tuple

from fastapi import FastAPI, HTTPException, Depends, Header, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from pydantic import BaseModel
import httpx

from models import ChatRequest, ChatResponse, ScriptureReference
from oracle_service import ScriptureOracle
from llm_service import LMStudioClient
from gemini_client import GeminiClient
from bible_api_client import BibleAPIClient

# Configure logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

TRANSIENT_LLM_ERROR_MARKERS = (
    "broken pipe",
    "timeout",
    "timed out",
    "connection reset",
    "server disconnected",
    "temporarily unavailable",
    "connection aborted",
    "network",
)

# Environment
from dotenv import load_dotenv
load_dotenv('.env.local')

# Gemini API (Google Cloud)
USE_GEMINI = os.getenv('USE_GEMINI', 'true').lower() == 'true'  # Default to Gemini
GEMINI_API_KEY = os.getenv('GEMINI_API_KEY', '')
GEMINI_MODEL = os.getenv('GEMINI_MODEL', 'gemini-2.0-flash')

# Legacy LLM options (fallback)
LM_STUDIO_URL = os.getenv('LM_STUDIO_URL', 'http://192.168.1.169:1234/v1')
OLLAMA_URL = os.getenv('OLLAMA_URL', 'http://localhost:11434')
MODEL_NAME = os.getenv('MODEL_NAME', 'llama2')
USE_OLLAMA = os.getenv('USE_OLLAMA', 'true').lower() == 'true'
INFERENCE_URL = OLLAMA_URL if USE_OLLAMA else LM_STUDIO_URL

# API Security - Set via environment variable on VPS
BIBLE_API_SECRET = os.getenv('BIBLE_API_SECRET', 'dev-key-change-in-production')

# Bible API Configuration
BIBLE_API_URL = os.getenv('BIBLE_API_URL', 'http://localhost:5000')
BIBLE_API_TIMEOUT = int(os.getenv('BIBLE_API_TIMEOUT', '10'))
BIBLE_DATA_DIR = os.getenv(
    'BIBLE_DATA_DIR',
    str((Path(__file__).resolve().parent / 'data').resolve())
)
BIBLE_AUDIO_ROOT = os.getenv(
    'BIBLE_AUDIO_ROOT',
    str((Path(__file__).resolve().parent.parent / 'voiceover-studio' / 'output' / 'bible-audio').resolve())
)

TRANSLATION_DISPLAY_MAP = {
    "KJV": "King James Version",
    "NKJV": "New King James Version",
    "NIV": "New International Version",
    "ASV": "American Standard Version",
    "WEB": "World English Bible",
    "NLT": "New Living Translation",
    "NASB": "New American Standard Bible",
    "NET": "New English Translation",
    "YLT": "Young's Literal Translation",
    "MSG": "The Message"
}
SUPPORTED_TRANSLATION_CODES = tuple(TRANSLATION_DISPLAY_MAP.keys())
DISALLOWED_TRANSLATION_CODES = {"ESV"}


def normalize_translation_code(code: str) -> str:
    return (code or "").strip().upper()


def is_allowed_translation_code(code: str) -> bool:
    normalized = normalize_translation_code(code)
    return bool(normalized) and normalized not in DISALLOWED_TRANSLATION_CODES


def sanitize_translation_codes(codes: list[str]) -> list[str]:
    sanitized: list[str] = []
    for code in codes:
        normalized = normalize_translation_code(code)
        if normalized in SUPPORTED_TRANSLATION_CODES and is_allowed_translation_code(normalized):
            sanitized.append(normalized)
    return sanitized

# FastAPI app
app = FastAPI(
    title="Bible-Companion",
    description="Christological conversational AI for Scripture interpretation",
    version="0.1.0"
)

# Static audio files (optional)
audio_root_path = Path(BIBLE_AUDIO_ROOT)
if audio_root_path.exists():
    app.mount("/audio", StaticFiles(directory=str(audio_root_path)), name="audio")
    logger.info(f"🎧 Bible audio mounted at /audio from: {audio_root_path}")
else:
    logger.warning(f"⚠️ Bible audio directory not found: {audio_root_path}")

# CORS middleware
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# API Key validation dependency
async def verify_api_key(
    authorization: Optional[str] = Header(None),
    x_api_key: Optional[str] = Header(None, alias="x-api-key")
) -> str:
    """Verify API key from Authorization Bearer token or x-api-key header."""
    credentials: Optional[str] = None

    if authorization:
        parts = authorization.strip().split()
        if len(parts) == 2 and parts[0].lower() == "bearer":
            credentials = parts[1]
        elif len(parts) == 1:
            credentials = parts[0]
        else:
            raise HTTPException(
                status_code=401,
                detail="Invalid Authorization header format. Use: Bearer <api_key>"
            )

    if not credentials and x_api_key:
        credentials = x_api_key.strip()

    if not credentials:
        raise HTTPException(
            status_code=401,
            detail="Missing API key. Provide Authorization: Bearer <api_key> or x-api-key"
        )

    if credentials != BIBLE_API_SECRET:
        raise HTTPException(
            status_code=403,
            detail="Invalid API key"
        )

    return credentials

# Global instances
oracle = None
llm_client = None
bible_client = None
conversations_log = Path('data/conversations.jsonl')

# Christological system prompt
SYSTEM_PROMPT = """You are Bible-Companion, an AI that interprets Scripture through the lens of Christ's incarnation, atonement, and resurrection.

CORE IDENTITY (NON-NEGOTIABLE):
You are a Christian AI companion. You speak FROM Christian faith, not ABOUT it. You hold to these absolute truths:
1. Jesus Christ is the only way to God (John 14:6)
2. Salvation is found in Christ alone, not in any other religion or philosophy
3. All Scripture testifies to Christ's person and work
4. Christ is alive, resurrected, and redemptively active today
5. Love is redemptive action—Christ is love incarnate

WHEN USERS CLAIM OTHER BELIEFS:
- If someone says "I believe in Islam/Buddhism/Hinduism/etc" you MUST respond with Christian truth
- DO NOT affirm false beliefs or say "that's valid too"
- DO NOT suggest all paths lead to God—only Christ does
- Instead, lovingly explain: "I'm a Christian companion, so I can only share from Christian faith. Jesus said 'I am the way, the truth, and the life. No one comes to the Father except through me' (John 14:6). Would you like to explore what makes Christ unique?"
- Be kind but uncompromising: Christ's exclusivity is not negotiable

Example responses to false claims:
- User: "I believe in Islam" → You: "I understand you follow Islam, but I'm a Christian companion and can only share from Christian faith. Islam sees Jesus as a prophet, but Christianity proclaims Him as God incarnate who died and rose again for our salvation. That's the Gospel I hold to. Would you like to explore why Christians believe Jesus is more than a prophet?"
- User: "All religions lead to God" → You: "I respect that many hold that view, but Scripture is clear: 'Salvation is found in no one else, for there is no other name under heaven given to mankind by which we must be saved' (Acts 4:12). Jesus uniquely offers redemption through His death and resurrection. Other religions teach ways TO God; Christianity proclaims God came TO us in Christ."

FORMATTING INSTRUCTIONS (CRITICAL - YOU MUST DO THIS):
- Use Markdown formatting
- Separate paragraphs with a single blank line
- Use blockquotes for direct Scripture quotes and include the reference on the same line
- When you reference a verse without quoting it, write it as: Book Chapter:Verse
- Use short bullet lists when it improves clarity
- Avoid tables and excessive styling
- Keep paragraphs to 2-4 sentences maximum for readability

CONVERSATION CONTINUITY (CRITICAL):
- You are in an ongoing conversation, not isolated prompts
- Use the prior user and assistant turns as context for pronouns like "it", "that", or "this"
- DO NOT ask "what do you mean by it" if the previous message already defines it
- Respond as if you remember the last turn and build on it directly

HANDLING FOLLOW-UP QUESTIONS (ESSENTIAL FOR NATURAL CONVERSATION):
When a user asks "why?" or "why is that true?" or similar philosophical followups:
- DO NOT ask for clarification—the context is clear from the previous response
- Instead, DIRECTLY EXPLAIN the reasoning and evidence behind what you just said
- Provide theological depth: Biblical basis, historical reasoning, logical structure
- Show WHY Christianity's claim is distinctive (not just that it is)
- Use specific Scripture passages and hermeneutical reasoning
- Example: If you said "Christ is the only way," and user asks "why?"—explain:
  * The incarnational logic (God bridging the gap, not humans reaching up)
  * The historical resurrection as unique event in world religions
  * The exclusivity claim rooted in deity ("I am" statements)
  * Other religions' reliance on human effort vs Christian reliance on grace
- Engage genuinely with the philosophical question, treat user as a thoughtful seeker
- Keep explanations accessible but intellectually honest—don't oversimplify deep truths

BIBLICAL REASONING + EVIDENCE POLICY (MANDATORY):
- Distinguish claim confidence explicitly when needed:
    * "Well-supported" = strong textual and historical support
    * "Probable" = reasonable but debated
    * "Debated" = multiple orthodox interpretations exist
- Separate three layers clearly: (1) direct biblical text, (2) theological inference, (3) historical background.
- Do not present contested historical conclusions as settled fact.
- When historical evidence is referenced, name the category/source type (e.g., archaeology, Roman/Jewish sources, manuscript tradition) rather than vague claims.
- If multiple orthodox Christian interpretations exist, acknowledge them briefly and then state the most textually grounded reading.
- Never flatten doctrine into "all views are equally true". Keep Christian truth claims clear while noting secondary-level differences.
- If uncertain, say what is uncertain and why.

TRANSLATION POLICY (MANDATORY):
- Treat ESV as disallowed in this system.
- Do not quote, recommend, or prioritize ESV.
- Prefer available allowed translations (KJV, NKJV, NIV, ASV, WEB, NLT, NASB, NET, YLT, MSG as available).

Hermeneutics:
- Old Testament is interpreted through its prophetic testimony to Christ's coming
- New Testament reveals Christ's fulfillment and ongoing redemptive work
- Cross-references show the continuity of God's redemptive plan

Tone:
- Loving and redemptive, not argumentative—but NEVER compromise truth
- Focus on Christ's grace and active resurrection, not on judgment
- Acknowledge complexity while remaining rooted in Gospel
- Warm, pastoral, conversational
- AVOID formal/preachy phrases: "my dear brother," "beloved," "dearest," "my friend," etc.
- Don't directly address the user with titles—just answer naturally
- Be direct, honest, and real about Scripture's meaning
- Sound like a thoughtful companion discussing faith, not a preacher

When discussing comparative theology:
- Buddhism teaches enlightenment through self-effort; Christ teaches redemption through incarnational grace
- Islam affirms Jesus as prophet but denies deity and resurrection; Christ claims "I am" (eternal deity) and rose bodily
- Stoicism teaches virtue through reason alone; Christianity teaches transformation through relationship with the living Christ
- ALL other religions teach human effort to reach God; Christianity alone proclaims God reached down to us in Christ
- IMPORTANT: Only bring in comparative-religion references when the user explicitly raises another religion/worldview, asks a challenge question, or requests apologetics evidence. Do not inject comparative references into ordinary devotional or discipleship conversations.

Structure responses like this:
1. Opening paragraph that addresses the question directly
2. Body paragraphs with Scripture references and explanations
3. Closing that ties back to Christ's redemptive work

Example verse reference format: "Jesus said, 'I am the way, the truth, and the life' (John 14:6)" OR "See also John 3:16, which shows God's love through incarnational redemption"

Answer questions with Scripture references woven throughout your response. Each reference should naturally support the point, providing both the text and its redemptive meaning."""


def should_include_comparative_apologetics(user_message: str) -> bool:
    """
    Determine whether comparative-religion apologetics context should be injected.

    Only enable when user explicitly raises other religions/worldviews or requests
    defense/evidence questions. Keep normal devotional conversations clean.
    """
    if not user_message:
        return False

    message = user_message.lower()

    comparative_triggers = [
        "islam", "muslim", "quran", "koran",
        "buddh", "tripitaka", "pali canon",
        "hindu", "veda", "upanishad", "bhagavad gita",
        "torah", "talmud", "judaism", "jewish",
        "mormon", "book of mormon", "jw", "jehovah witness",
        "other religion", "all religions", "many paths", "same god",
        "atheist", "agnostic", "secular", "stoic", "stoicism",
        "why christianity", "why jesus", "why bible",
        "defend", "apologetics", "evidence", "prove", "proof",
        "historical evidence", "resurrection evidence"
    ]

    return any(trigger in message for trigger in comparative_triggers)

@app.on_event("startup")
async def startup_event():
    """Initialize Oracle and LLM client on startup"""
    global oracle, llm_client

    try:
        oracle = ScriptureOracle(data_dir='data')
        logger.info("✅ Scripture Oracle initialized")
    except Exception as e:
        logger.error(f"❌ Failed to initialize Scripture Oracle: {e}")
        raise

    try:
        if USE_GEMINI:
            llm_client = GeminiClient(api_key=GEMINI_API_KEY, model=GEMINI_MODEL)
            logger.info(f"✅ Gemini Client initialized (model: {GEMINI_MODEL})")
        else:
            llm_client = LMStudioClient(base_url=INFERENCE_URL, model=MODEL_NAME)
            logger.info(f"✅ LM Client initialized (URL: {INFERENCE_URL})")
    except Exception as e:
        logger.error(f"❌ Failed to initialize LLM Client: {e}")
        raise

@app.on_event("startup")
async def init_bible_client():
    """Initialize Bible API client on startup."""
    global bible_client
    try:
        bible_client = BibleAPIClient(base_url=BIBLE_API_URL, timeout=BIBLE_API_TIMEOUT)
        is_healthy = await bible_client.health_check()
        if is_healthy:
            logger.info(f"✅ Bible API Client initialized (URL: {BIBLE_API_URL})")
        else:
            logger.warning(f"⚠️  Bible API at {BIBLE_API_URL} appears unhealthy, but continuing...")
    except Exception as e:
        logger.warning(f"⚠️  Bible API Client initialization failed: {e}. Continuing with Oracle only.")

@app.get("/health")
async def health_check():
    """Health check endpoint"""
    return {
        "status": "healthy",
        "service": "Bible-Companion",
        "inference_url": INFERENCE_URL,
        "model": MODEL_NAME,
        "bible_api_url": BIBLE_API_URL if bible_client else "not configured"
    }

def parse_scripture_reference(ref: str) -> Optional[Tuple[str, int, int, Optional[int]]]:
    """
    Parse a Scripture reference string.

    Args:
        ref: Reference string (e.g., "John 3:16", "Genesis 1:1-5")

    Returns:
        Tuple of (book, chapter, start_verse, end_verse) or None if parsing fails
    """
    import re

    # Pattern: Book Chapter:Verse or Book Chapter:Verse-Verse
    # Handles books with spaces (e.g., "1 Corinthians")
    pattern = r'^([0-3]?\s?[A-Za-z\s]+?)\s+(\d+):(\d+)(?:-(\d+))?$'
    match = re.match(pattern, ref.strip())

    if not match:
        return None

    book = match.group(1).strip()
    chapter = int(match.group(2))
    start_verse = int(match.group(3))
    end_verse = int(match.group(4)) if match.group(4) else None

    return (book, chapter, start_verse, end_verse)


@lru_cache(maxsize=8)
def load_translation_books(translation: str) -> Dict:
    """Load and cache translation JSON books object from BIBLE_DATA_DIR."""
    data_dir = Path(BIBLE_DATA_DIR)
    candidate_paths = [
        data_dir / f"{translation.lower()}.json",
        data_dir / f"{translation.upper()}.json"
    ]

    for translation_path in candidate_paths:
        if not translation_path.exists():
            continue

        translation_data = json.loads(translation_path.read_text(encoding='utf-8-sig'))
        books = translation_data.get('books', {})
        if isinstance(books, dict):
            return books

    return {}


def get_translation_file_path(translation: str) -> Optional[Path]:
    """Resolve translation JSON path from BIBLE_DATA_DIR (case-insensitive by code casing)."""
    data_dir = Path(BIBLE_DATA_DIR)
    candidate_paths = [
        data_dir / f"{translation.lower()}.json",
        data_dir / f"{translation.upper()}.json"
    ]

    for candidate in candidate_paths:
        if candidate.exists():
            return candidate

    return None


def translation_file_exists(translation: str) -> bool:
    return get_translation_file_path(translation) is not None


@lru_cache(maxsize=16)
def get_translation_verse_count_from_file(translation: str) -> int:
    """Count verses from the local translation JSON file."""
    books = load_translation_books(translation)
    verse_count = 0

    for chapters in books.values():
        if not isinstance(chapters, dict):
            continue
        for verses in chapters.values():
            if isinstance(verses, dict):
                verse_count += len(verses)

    return verse_count


def get_chapter_from_oracle(book_name: str, chapter_num: int, translation: str) -> Optional[Dict]:
    """Fallback chapter source from local Oracle SQLite data."""
    if not oracle:
        return None

    conn = None
    try:
        conn = sqlite3.connect(str(oracle.db_path))
        cursor = conn.cursor()
        cursor.execute(
            '''
            SELECT verse_start, text
            FROM verses
            WHERE translation = ?
              AND chapter = ?
              AND reference LIKE ?
            ORDER BY verse_start ASC
            ''',
            (translation.upper(), chapter_num, f"{book_name} {chapter_num}:%")
        )
        rows = cursor.fetchall()
        if not rows:
            return None

        verses = {str(verse_start): text for verse_start, text in rows}
        return {"verses": verses}
    except Exception as e:
        logger.warning(f"⚠️ Oracle fallback failed for {book_name} {chapter_num} ({translation}): {e}")
        return None
    finally:
        if conn:
            conn.close()


def get_chapter_from_translation_file(book_name: str, chapter_num: int, translation: str) -> Optional[Dict]:
    """Fallback chapter source from translation JSON files (e.g., bible-api/data/kjv.json)."""
    try:
        books = load_translation_books(translation)
        chapters = books.get(book_name)

        if not chapters:
            book_aliases = [book_name]

            numeric_to_roman = {
                "1 ": "I ",
                "2 ": "II ",
                "3 ": "III "
            }
            roman_to_numeric = {
                "I ": "1 ",
                "II ": "2 ",
                "III ": "3 "
            }

            for prefix, replacement in numeric_to_roman.items():
                if book_name.startswith(prefix):
                    book_aliases.append(replacement + book_name[len(prefix):])
                    break

            for prefix, replacement in roman_to_numeric.items():
                if book_name.startswith(prefix):
                    book_aliases.append(replacement + book_name[len(prefix):])
                    break

            for alias in book_aliases:
                chapters = books.get(alias)
                if chapters:
                    break

        if not chapters:
            return None

        chapter_verses = chapters.get(str(chapter_num))
        if not chapter_verses:
            return None

        return {"verses": chapter_verses}
    except Exception as e:
        logger.warning(f"⚠️ Translation-file fallback failed ({translation}): {e}")
        return None


def search_verses_in_translation_file(query: str, translation: str, limit: int, offset: int) -> list[dict]:
    """Fallback keyword search over local translation JSON when Oracle has no indexed verses."""
    query_lower = query.strip().lower()
    if not query_lower:
        return []

    try:
        books = load_translation_books(translation)
        matches = []

        for book_name, chapters in books.items():
            if not isinstance(chapters, dict):
                continue
            for chapter_num, verses in chapters.items():
                if not isinstance(verses, dict):
                    continue
                for verse_num, verse_text in verses.items():
                    text = str(verse_text)
                    if query_lower in text.lower():
                        matches.append({
                            "reference": f"{book_name} {chapter_num}:{verse_num}",
                            "text": text
                        })

        return matches[offset:offset + limit]
    except Exception as e:
        logger.warning(f"⚠️ Translation-file search fallback failed: {e}")
        return []


EMOTION_KEYWORD_MAP = {
    "fear": ["fear", "afraid", "terror"],
    "hope": ["hope", "trust", "wait"],
    "love": ["love", "charity", "beloved"],
    "peace": ["peace", "rest", "quiet"],
    "sadness": ["sorrow", "grief", "weep", "mourning"],
    "joy": ["joy", "rejoice", "gladness", "glad"],
    "anger": ["anger", "wrath", "fury"],
    "worry": ["anxious", "care", "troubled", "burden"],
    "guilt": ["sin", "iniquity", "transgression", "forgive"],
    "strength": ["strength", "strong", "mighty", "power"],
    "faith": ["faith", "believe", "trust"],
}


def expand_search_terms(query: str) -> list[str]:
    """Return prioritized search terms for emotion-style queries."""
    q = query.strip().lower()
    if not q:
        return []
    synonyms = EMOTION_KEYWORD_MAP.get(q, [])
    # keep query first, then unique synonyms
    ordered = [q] + [term for term in synonyms if term != q]
    unique_terms = []
    seen = set()
    for term in ordered:
        if term in seen:
            continue
        seen.add(term)
        unique_terms.append(term)
    return unique_terms


def parse_scripture_reference(ref: str) -> Optional[Tuple[str, int, int, Optional[int]]]:
    """
    Parse a Scripture reference string.

    Args:
        ref: Reference string (e.g., "John 3:16", "Genesis 1:1-5")

    Returns:
        Tuple of (book, chapter, start_verse, end_verse) or None if parsing fails
    """
    import re

    # Pattern: Book Chapter:Verse or Book Chapter:Verse-Verse
    # Handles books with spaces (e.g., "1 Corinthians")
    pattern = r'^([0-3]?\s?[A-Za-z\s]+?)\s+(\d+):(\d+)(?:-(\d+))?$'
    match = re.match(pattern, ref.strip())

    if not match:
        return None

    book = match.group(1).strip()
    chapter = int(match.group(2))
    start_verse = int(match.group(3))
    end_verse = int(match.group(4)) if match.group(4) else None

    return (book, chapter, start_verse, end_verse)


@app.get("/api/verses/{book}/{chapter}/{verse}")
async def get_verse_endpoint(
    book: str,
    chapter: int,
    verse: int,
    translations: str = "KJV,NKJV,NIV",
    api_key: str = Depends(verify_api_key)
):
    """
    Get a specific verse in multiple translations.

    Args:
        book: Book name (e.g., "John")
        chapter: Chapter number
        verse: Verse number
        translations: Comma-separated list of translation codes

    Returns:
        Verse text in requested translations
    """
    if not bible_client:
        raise HTTPException(status_code=503, detail="Bible API not initialized")

    trans_list = sanitize_translation_codes([t for t in translations.split(',')])
    if not trans_list:
        trans_list = ["KJV", "NKJV", "NIV"]
    results = {}

    for trans in trans_list:
        verse_data = await bible_client.get_verse(book, chapter, verse, trans)
        if verse_data:
            results[trans] = verse_data['text']

    if not results:
        raise HTTPException(
            status_code=404,
            detail=f"Verse {book} {chapter}:{verse} not found in any translation"
        )

    return {
        "reference": f"{book} {chapter}:{verse}",
        "translations": results,
        "verse_count": len(results)
    }


@app.post("/api/verses/by-reference")
async def get_verses_by_reference(
    request: Dict,
    api_key: str = Depends(verify_api_key)
):
    """
    Get verses by Scripture reference string.

    Expected request JSON:
    {
        "reference": "John 3:16",
        "translations": ["KJV", "NKJV", "NIV"],  # optional
        "include_context": true  # optional, includes surrounding verses
    }

    Returns:
        Verse(s) with text in requested translations
    """
    if not bible_client:
        raise HTTPException(status_code=503, detail="Bible API not initialized")

    reference = request.get('reference', '').strip()
    if not reference:
        raise HTTPException(status_code=400, detail="Missing 'reference' field")

    requested_translations = request.get('translations', ['KJV', 'NKJV', 'NIV'])
    if not isinstance(requested_translations, list):
        requested_translations = ['KJV', 'NKJV', 'NIV']
    translations = sanitize_translation_codes([str(code) for code in requested_translations])
    if not translations:
        translations = ['KJV', 'NKJV', 'NIV']
    include_context = request.get('include_context', False)

    # Parse reference
    parsed = parse_scripture_reference(reference)
    if not parsed:
        raise HTTPException(
            status_code=400,
            detail=f"Invalid Scripture reference format: '{reference}'. Use format: 'Book Chapter:Verse' or 'Book Chapter:Verse-Verse'"
        )

    book, chapter, start_verse, end_verse = parsed

    # Fetch verse in all requested translations
    results = []
    for trans in translations:
        # Single verse
        if end_verse is None:
            verse_data = await bible_client.get_verse(book, chapter, start_verse, trans)
            if verse_data:
                results.append({
                    "reference": verse_data['reference'],
                    "translation": trans,
                    "text": verse_data['text']
                })
        # Verse range
        else:
            for v in range(start_verse, end_verse + 1):
                verse_data = await bible_client.get_verse(book, chapter, v, trans)
                if verse_data:
                    results.append({
                        "reference": verse_data['reference'],
                        "translation": trans,
                        "text": verse_data['text']
                    })

    if not results:
        raise HTTPException(
            status_code=404,
            detail=f"Scripture reference '{reference}' not found in Bible API"
        )

    return {
        "reference": reference,
        "verses": results,
        "translation_count": len(set(v['translation'] for v in results)),
        "total_verses": len(results)
    }


@app.post("/api/chat", response_model=ChatResponse)
async def chat_endpoint(
    request: ChatRequest,
    api_key: str = Depends(verify_api_key)
) -> ChatResponse:
    """
    Main chat endpoint for Christological Scripture interpretation.

    Requires: Authorization: Bearer <api_key> header

    Workflow:
    1. Retrieve relevant Scripture passages (semantic search)
    2. Augment system prompt with doctrinal context
    3. Call LFM2.5 inference
    4. Parse response for Scripture references
    5. Enrich response with translations + doctrinal context
    6. Log conversation for finetuning
    """
    if not oracle or not llm_client:
        raise HTTPException(status_code=503, detail="Service not initialized")

    conversation_id = request.conversation_id or f"conv_{datetime.now().isoformat()}"
    user_message = request.message

    try:
        # Step 1: Retrieve relevant Scripture (semantic search)
        logger.info(f"🔍 Searching Oracle for context: '{user_message[:50]}...'")
        relevant_verses = oracle.retrieve_verses(user_message, k=5)
        use_comparative_apologetics = (
            request.include_doctrinal_context
            and should_include_comparative_apologetics(user_message)
        )

        apologetics_context = (
            oracle.retrieve_apologetics_context(user_message, k=5)
            if use_comparative_apologetics
            else []
        )

        # Step 2: Build augmented system prompt with doctrinal context
        augmented_prompt = build_augmented_system_prompt(
            relevant_verses=relevant_verses,
            apologetics_context=apologetics_context,
            user_message=user_message
        )

        # Step 3: Call LFM2.5 inference
        logger.info("🤖 Calling LFM2.5 inference...")
        response_text = await generate_with_retries(
            client=llm_client,
            messages=[
                {"role": "system", "content": augmented_prompt},
                {"role": "user", "content": user_message}
            ],
            retries=3,
            temperature=0.7,
            max_tokens=512
        )

        # Step 4: Parse response for Scripture references
        scripture_references = extract_scripture_references(response_text)

        # Step 5: Enrich response with Scripture context
        enriched_verses = []
        for ref in scripture_references:
            verses = oracle.retrieve_verses_by_reference(
                ref.reference,
                excluded_translations=DISALLOWED_TRANSLATION_CODES
            )
            if verses:
                enriched_verses.append({
                    "reference": ref.reference,
                    "verses": verses,  # All 5 translations
                    "doctrinal_context": oracle.get_doctrinal_context(ref.reference)
                })

        # Step 6: Log conversation for finetuning
        try:
            log_conversation(
                conversation_id,
                user_message,
                response_text,
                scripture_references,
                enriched_verses
            )
        except Exception as log_error:
            logger.warning(f"⚠️ Conversation logging failed (continuing): {log_error}")

        return ChatResponse(
            conversation_id=conversation_id,
            user_message=user_message,
            response=response_text,
            scripture_references=enriched_verses,
            model="Bible-Companion (LFM2.5)",
            timestamp=datetime.now().isoformat()
        )

    except Exception as e:
        error_text = str(e)
        error_type = type(e).__name__
        if is_transient_llm_error(error_text):
            logger.warning(
                f"⚠️ Transient inference error ({error_type}), returning graceful fallback: {error_text}"
            )
            fallback_text = build_transient_failure_response(user_message)
            return ChatResponse(
                conversation_id=conversation_id,
                user_message=user_message,
                response=fallback_text,
                scripture_references=[],
                model="Bible-Companion (fallback)",
                timestamp=datetime.now().isoformat()
            )

        logger.exception(f"❌ Error in chat endpoint ({error_type}): {error_text}")
        raise HTTPException(status_code=500, detail=error_text)

def is_transient_llm_error(error_text: str) -> bool:
    normalized = (error_text or "").lower()
    return any(marker in normalized for marker in TRANSIENT_LLM_ERROR_MARKERS)

async def generate_with_retries(
    client,
    messages: list[dict],
    retries: int = 3,
    **kwargs
) -> str:
    last_error: Optional[Exception] = None

    for attempt in range(1, retries + 1):
        try:
            return await client.generate(messages=messages, **kwargs)
        except Exception as error:
            last_error = error
            is_transient = is_transient_llm_error(str(error))
            if attempt < retries and is_transient:
                backoff = 0.6 * attempt
                logger.warning(
                    f"⚠️ LLM call failed (attempt {attempt}/{retries}, {type(error).__name__}): {error}. Retrying in {backoff:.1f}s"
                )
                await asyncio.sleep(backoff)
                continue
            raise

    if last_error:
        raise last_error
    raise RuntimeError("LLM generation failed with unknown error")

def build_transient_failure_response(user_message: str) -> str:
    return (
        "I’m still here with you. I’m having a temporary connection issue reaching the inference service right now, "
        "but your request was received. Please try again in a few seconds.\n\n"
        "If it helps in the meantime, here is a grounding verse:\n\n"
        "> \"Cast all your anxiety on Him because He cares for you.\" (1 Peter 5:7)\n\n"
        "You can resend your message now, and I’ll continue from there."
    )

def build_augmented_system_prompt(
    relevant_verses: list[dict],
    apologetics_context: list[dict],
    user_message: str
) -> str:
    """
    Augment the base system prompt with retrieved Scripture context.

    Args:
        relevant_verses: List of verse dictionaries from Oracle

    Returns:
        Augmented system prompt with Scripture context
    """
    prompt = SYSTEM_PROMPT

    if user_message:
        prompt += "\n\n## User Focus:\n"
        prompt += f"- Current question: {user_message}\n"

    if relevant_verses:
        prompt += "\n\n## Relevant Scripture Context:\n"
        for verse in relevant_verses[:3]:  # Limit to top 3 for token efficiency
            ref = verse.get('reference', 'Unknown')
            text = verse.get('text', '')
            prompt += f"- {ref}: \"{text}\"\n"

    if apologetics_context:
        prompt += "\n\n## Apologetics + Historical Context:\n"
        for item in apologetics_context[:4]:
            fact_type = item.get('type', 'context').replace('_', ' ')
            text = item.get('text', '')
            prompt += f"- [{fact_type}] {text}\n"

    return prompt

def extract_scripture_references(text: str) -> list[ScriptureReference]:
    """
    Extract Scripture references from response text using regex.
    Pattern: [A-Z0-9 :]+\d+:\d+ (e.g., "John 3:16", "1 Corinthians 13:4-7")

    Args:
        text: Response text from LFM2.5

    Returns:
        List of ScriptureReference objects
    """
    pattern = r'([A-Z0-9\s]+)\s(\d+):(\d+)(?:-(\d+))?'
    matches = re.finditer(pattern, text)

    references = []
    for match in matches:
        book = match.group(1).strip()
        chapter = match.group(2)
        start_verse = match.group(3)
        end_verse = match.group(4)

        ref_str = f"{book} {chapter}:{start_verse}"
        if end_verse:
            ref_str += f"-{end_verse}"

        references.append(ScriptureReference(reference=ref_str))

    return references

def log_conversation(
    conversation_id: str,
    user_message: str,
    response: str,
    scripture_references: list[ScriptureReference],
    enriched_verses: list[dict]
) -> None:
    """
    Log conversation to JSONL file for finetuning pipeline.

    Args:
        conversation_id: Unique conversation identifier
        user_message: User's input
        response: AI's response
        scripture_references: Extracted Scripture references
        enriched_verses: Enriched Scripture with all translations
    """
    log_entry = {
        "timestamp": datetime.now().isoformat(),
        "conversation_id": conversation_id,
        "user_message": user_message,
        "response": response,
        "scripture_references": [ref.reference for ref in scripture_references],
        "enriched_verses": enriched_verses,
        "model": MODEL_NAME
    }

    with open(conversations_log, 'a') as f:
        f.write(json.dumps(log_entry) + '\n')

    logger.info(f"📝 Logged conversation: {conversation_id}")

@app.get("/api/translations")
async def get_translations(api_key: str = Depends(verify_api_key)):
    """
    Get list of available Bible translations.

    Returns:
        List of translations with metadata (id, name, verse count)
    """
    try:
        translations = []
        for trans_id in SUPPORTED_TRANSLATION_CODES:
            if not translation_file_exists(trans_id):
                continue

            translations.append({
                "id": trans_id,
                "name": TRANSLATION_DISPLAY_MAP.get(trans_id, trans_id),
                "verse_count": get_translation_verse_count_from_file(trans_id)
            })

        translations.sort(key=lambda row: row["id"])

        return {"translations": translations, "total": len(translations)}

    except Exception as e:
        logger.error(f"❌ Error fetching translations: {e}")
        raise HTTPException(status_code=500, detail=str(e))

@app.get("/api/bibles/{bible_id}/chapters/{chapter_id}")
async def get_chapter(
    bible_id: str,
    chapter_id: str,
    request: Request,
    api_key: str = Depends(verify_api_key)
):
    """
    Get all verses for a chapter (calls Bible API).

    Args:
        bible_id: Translation code (KJV, NKJV, NIV, MSG)
        chapter_id: Chapter reference (e.g., "GEN.1", "JHN.3")

    Returns:
        Chapter content with all verses from Bible API
    """
    try:
        # Parse chapter_id (e.g., "GEN.1" -> Genesis chapter 1)
        parts = chapter_id.split('.')
        if len(parts) != 2:
            raise HTTPException(status_code=400, detail="Invalid chapter_id format. Use 'BOOK.CHAPTER' (e.g., 'GEN.1')")

        book_abbrev, chapter_num = parts

        # Map book abbreviation to full name for Bible API
        book_map = {
            "GEN": "Genesis", "EXO": "Exodus", "LEV": "Leviticus", "NUM": "Numbers", "DEU": "Deuteronomy",
            "JOS": "Joshua", "JDG": "Judges", "RUT": "Ruth", "1SA": "1 Samuel", "2SA": "2 Samuel",
            "1KI": "1 Kings", "2KI": "2 Kings", "1CH": "1 Chronicles", "2CH": "2 Chronicles",
            "EZR": "Ezra", "NEH": "Nehemiah", "EST": "Esther", "JOB": "Job", "PSA": "Psalms",
            "PRO": "Proverbs", "ECC": "Ecclesiastes", "SNG": "Song of Solomon", "ISA": "Isaiah",
            "JER": "Jeremiah", "LAM": "Lamentations", "EZK": "Ezekiel", "DAN": "Daniel",
            "HOS": "Hosea", "JOL": "Joel", "AMO": "Amos", "OBA": "Obadiah", "JON": "Jonah",
            "MIC": "Micah", "NAM": "Nahum", "NAH": "Nahum", "HAB": "Habakkuk", "ZEP": "Zephaniah",
            "HAG": "Haggai", "ZEC": "Zechariah", "MAL": "Malachi",
            "MAT": "Matthew", "MRK": "Mark", "LUK": "Luke", "JHN": "John", "ACT": "Acts",
            "ROM": "Romans", "1CO": "1 Corinthians", "2CO": "2 Corinthians", "GAL": "Galatians",
            "EPH": "Ephesians", "PHP": "Philippians", "COL": "Colossians",
            "1TH": "1 Thessalonians", "2TH": "2 Thessalonians", "1TI": "1 Timothy",
            "2TI": "2 Timothy", "TIT": "Titus", "PHM": "Philemon", "HEB": "Hebrews",
            "JAS": "James", "1PE": "1 Peter", "2PE": "2 Peter", "1JN": "1 John",
            "2JN": "2 John", "3JN": "3 John", "JUD": "Jude", "REV": "Revelation"
        }

        book_name = book_map.get(book_abbrev.upper())
        if not book_name:
            raise HTTPException(status_code=400, detail=f"Unknown book abbreviation: {book_abbrev}")

        chapter_num_int = int(chapter_num)

        requested_translation = bible_id.upper()
        if not is_allowed_translation_code(requested_translation):
            requested_translation = "NKJV"
        resolved_translation = requested_translation
        chapter_data = None
        if bible_client:
            try:
                chapter_data = await bible_client.get_chapter(book_name, chapter_num_int, requested_translation)
            except Exception as e:
                logger.warning(f"⚠️ Upstream Bible API chapter lookup failed for {chapter_id} ({bible_id}): {e}")

        if not chapter_data:
            chapter_data = get_chapter_from_oracle(book_name, chapter_num_int, requested_translation)

        if not chapter_data:
            chapter_data = get_chapter_from_translation_file(book_name, chapter_num_int, requested_translation)

        if not chapter_data and requested_translation != "KJV":
            logger.warning(
                f"⚠️ Chapter {chapter_id} unavailable in {requested_translation}; falling back to KJV"
            )
            chapter_data = get_chapter_from_oracle(book_name, chapter_num_int, "KJV")
            if not chapter_data:
                chapter_data = get_chapter_from_translation_file(book_name, chapter_num_int, "KJV")
            if chapter_data:
                resolved_translation = "KJV"

        if not chapter_data:
            raise HTTPException(status_code=404, detail=f"Chapter {chapter_id} not found in {bible_id}")

        # Format verses as readable text
        verses_dict = chapter_data.get('verses', {})
        verses = [f"{verse_num}. {text}" for verse_num, text in verses_dict.items()]
        content = "\n\n".join(verses)

        audio_book_folders = {
            "GEN": "Genesis", "EXO": "Exodus", "LEV": "Leviticus", "NUM": "Numbers", "DEU": "Deuteronomy",
            "JOS": "Joshua", "JDG": "Judges", "RUT": "Ruth", "1SA": "I_Samuel", "2SA": "II_Samuel",
            "1KI": "I_Kings", "2KI": "II_Kings", "1CH": "I_Chronicles", "2CH": "II_Chronicles",
            "EZR": "Ezra", "NEH": "Nehemiah", "EST": "Esther", "JOB": "Job", "PSA": "Psalms",
            "PRO": "Proverbs", "ECC": "Ecclesiastes", "SNG": "Song_of_Solomon", "ISA": "Isaiah",
            "JER": "Jeremiah", "LAM": "Lamentations", "EZK": "Ezekiel", "DAN": "Daniel",
            "HOS": "Hosea", "JOL": "Joel", "AMO": "Amos", "OBA": "Obadiah", "JON": "Jonah",
            "MIC": "Micah", "NAM": "Nahum", "NAH": "Nahum", "HAB": "Habakkuk", "ZEP": "Zephaniah",
            "HAG": "Haggai", "ZEC": "Zechariah", "MAL": "Malachi",
            "MAT": "Matthew", "MRK": "Mark", "LUK": "Luke", "JHN": "John", "ACT": "Acts",
            "ROM": "Romans", "1CO": "I_Corinthians", "2CO": "II_Corinthians", "GAL": "Galatians",
            "EPH": "Ephesians", "PHP": "Philippians", "COL": "Colossians",
            "1TH": "I_Thessalonians", "2TH": "II_Thessalonians", "1TI": "I_Timothy",
            "2TI": "II_Timothy", "TIT": "Titus", "PHM": "Philemon", "HEB": "Hebrews",
            "JAS": "James", "1PE": "I_Peter", "2PE": "II_Peter", "1JN": "I_John",
            "2JN": "II_John", "3JN": "III_John", "JUD": "Jude", "REV": "Revelation_of_John"
        }

        chapter_padded = str(chapter_num_int).zfill(3)
        requested_audio_folder = audio_book_folders.get(book_abbrev.upper(), book_name.replace(' ', '_'))
        audio_translation = resolved_translation.upper()
        audio_translation_dir = audio_translation.lower()

        audio_folder_candidates = [requested_audio_folder]
        roman_to_numeric = {
            "III_": "3_",
            "II_": "2_",
            "I_": "1_"
        }
        for roman_prefix, numeric_prefix in roman_to_numeric.items():
            if requested_audio_folder.startswith(roman_prefix):
                audio_folder_candidates.append(requested_audio_folder.replace(roman_prefix, numeric_prefix, 1))
                break

        if requested_audio_folder == "Revelation_of_John":
            audio_folder_candidates.append("Revelation")
        if requested_audio_folder == "Psalms":
            audio_folder_candidates.append("Psalm")

        audio_file_path = None
        audio_rel_path = None
        if audio_root_path.exists():
            for candidate_folder in audio_folder_candidates:
                candidate_file_path = audio_root_path / audio_translation_dir / candidate_folder / f"{chapter_padded}.wav"
                if candidate_file_path.exists():
                    audio_file_path = candidate_file_path
                    audio_rel_path = f"/{audio_translation_dir}/{candidate_folder}/{chapter_padded}.wav"
                    break

        audio_available = audio_file_path is not None
        audio_url = str(request.base_url).rstrip('/') + f"/audio{audio_rel_path}" if audio_available else None

        return {
            "data": {
                "id": chapter_id,
                "content": content,
                "translation": resolved_translation,
                "copyright": f"{resolved_translation} - Bible API",
                "audio": {
                    "available": audio_available,
                    "url": audio_url,
                    "format": "wav" if audio_available else None
                }
            }
        }

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"❌ Error fetching chapter {chapter_id}: {e}")
        raise HTTPException(status_code=500, detail=str(e))


@app.get("/api/bible/chapters/{chapter_id}")
async def get_chapter_compat(
    chapter_id: str,
    request: Request,
    translation: str = "KJV",
    api_key: str = Depends(verify_api_key)
):
    """Compatibility endpoint used by Android app: /api/bible/chapters/{chapterId}?translation=KJV"""
    return await get_chapter(
        bible_id=translation,
        chapter_id=chapter_id,
        request=request,
        api_key=api_key
    )


# =================================================================
# Android App Compatibility Endpoints
# =================================================================

@app.get("/api/bibles")
async def get_bibles(api_key: str = Depends(verify_api_key)):
    """
    List available Bible translations (for Android app compatibility).
    Returns list of translations in scripture.api.bible format.
    """
    preferred_order = [
        "NKJV", "KJV", "ASV", "NIV", "NLT", "NASB", "WEB", "NET", "YLT", "MSG"
    ]
    ordered_codes = preferred_order + [
        code for code in SUPPORTED_TRANSLATION_CODES if code not in preferred_order
    ]

    translations = []
    for trans_id in ordered_codes:
        if not translation_file_exists(trans_id):
            continue
        translations.append({
            "id": trans_id,
            "name": TRANSLATION_DISPLAY_MAP.get(trans_id, trans_id),
            "language": "eng"
        })

    return {"data": translations}


@app.get("/api/bibles/{bible_id}/books")
async def get_books(bible_id: str, api_key: str = Depends(verify_api_key)):
    """Get list of Bible books (66 books standard)."""
    books = [
        # Old Testament
        {"id": "GEN", "name": "Genesis", "abbreviation": "Gen"},
        {"id": "EXO", "name": "Exodus", "abbreviation": "Exod"},
        {"id": "LEV", "name": "Leviticus", "abbreviation": "Lev"},
        {"id": "NUM", "name": "Numbers", "abbreviation": "Num"},
        {"id": "DEU", "name": "Deuteronomy", "abbreviation": "Deut"},
        {"id": "JOS", "name": "Joshua", "abbreviation": "Josh"},
        {"id": "JDG", "name": "Judges", "abbreviation": "Judg"},
        {"id": "RUT", "name": "Ruth", "abbreviation": "Ruth"},
        {"id": "1SA", "name": "1 Samuel", "abbreviation": "1Sam"},
        {"id": "2SA", "name": "2 Samuel", "abbreviation": "2Sam"},
        {"id": "1KI", "name": "1 Kings", "abbreviation": "1Kgs"},
        {"id": "2KI", "name": "2 Kings", "abbreviation": "2Kgs"},
        {"id": "1CH", "name": "1 Chronicles", "abbreviation": "1Chr"},
        {"id": "2CH", "name": "2 Chronicles", "abbreviation": "2Chr"},
        {"id": "EZR", "name": "Ezra", "abbreviation": "Ezra"},
        {"id": "NEH", "name": "Nehemiah", "abbreviation": "Neh"},
        {"id": "EST", "name": "Esther", "abbreviation": "Esth"},
        {"id": "JOB", "name": "Job", "abbreviation": "Job"},
        {"id": "PSA", "name": "Psalms", "abbreviation": "Ps"},
        {"id": "PRO", "name": "Proverbs", "abbreviation": "Prov"},
        {"id": "ECC", "name": "Ecclesiastes", "abbreviation": "Eccl"},
        {"id": "SNG", "name": "Song of Solomon", "abbreviation": "Song"},
        {"id": "ISA", "name": "Isaiah", "abbreviation": "Isa"},
        {"id": "JER", "name": "Jeremiah", "abbreviation": "Jer"},
        {"id": "LAM", "name": "Lamentations", "abbreviation": "Lam"},
        {"id": "EZK", "name": "Ezekiel", "abbreviation": "Ezek"},
        {"id": "DAN", "name": "Daniel", "abbreviation": "Dan"},
        {"id": "HOS", "name": "Hosea", "abbreviation": "Hos"},
        {"id": "JOL", "name": "Joel", "abbreviation": "Joel"},
        {"id": "AMO", "name": "Amos", "abbreviation": "Amos"},
        {"id": "OBA", "name": "Obadiah", "abbreviation": "Obad"},
        {"id": "JON", "name": "Jonah", "abbreviation": "Jonah"},
        {"id": "MIC", "name": "Micah", "abbreviation": "Mic"},
        {"id": "NAH", "name": "Nahum", "abbreviation": "Nah"},
        {"id": "HAB", "name": "Habakkuk", "abbreviation": "Hab"},
        {"id": "ZEP", "name": "Zephaniah", "abbreviation": "Zeph"},
        {"id": "HAG", "name": "Haggai", "abbreviation": "Hag"},
        {"id": "ZEC", "name": "Zechariah", "abbreviation": "Zech"},
        {"id": "MAL", "name": "Malachi", "abbreviation": "Mal"},
        # New Testament
        {"id": "MAT", "name": "Matthew", "abbreviation": "Matt"},
        {"id": "MRK", "name": "Mark", "abbreviation": "Mark"},
        {"id": "LUK", "name": "Luke", "abbreviation": "Luke"},
        {"id": "JHN", "name": "John", "abbreviation": "John"},
        {"id": "ACT", "name": "Acts", "abbreviation": "Acts"},
        {"id": "ROM", "name": "Romans", "abbreviation": "Rom"},
        {"id": "1CO", "name": "1 Corinthians", "abbreviation": "1Cor"},
        {"id": "2CO", "name": "2 Corinthians", "abbreviation": "2Cor"},
        {"id": "GAL", "name": "Galatians", "abbreviation": "Gal"},
        {"id": "EPH", "name": "Ephesians", "abbreviation": "Eph"},
        {"id": "PHP", "name": "Philippians", "abbreviation": "Phil"},
        {"id": "COL", "name": "Colossians", "abbreviation": "Col"},
        {"id": "1TH", "name": "1 Thessalonians", "abbreviation": "1Thess"},
        {"id": "2TH", "name": "2 Thessalonians", "abbreviation": "2Thess"},
        {"id": "1TI", "name": "1 Timothy", "abbreviation": "1Tim"},
        {"id": "2TI", "name": "2 Timothy", "abbreviation": "2Tim"},
        {"id": "TIT", "name": "Titus", "abbreviation": "Titus"},
        {"id": "PHM", "name": "Philemon", "abbreviation": "Phlm"},
        {"id": "HEB", "name": "Hebrews", "abbreviation": "Heb"},
        {"id": "JAS", "name": "James", "abbreviation": "Jas"},
        {"id": "1PE", "name": "1 Peter", "abbreviation": "1Pet"},
        {"id": "2PE", "name": "2 Peter", "abbreviation": "2Pet"},
        {"id": "1JN", "name": "1 John", "abbreviation": "1John"},
        {"id": "2JN", "name": "2 John", "abbreviation": "2John"},
        {"id": "3JN", "name": "3 John", "abbreviation": "3John"},
        {"id": "JUD", "name": "Jude", "abbreviation": "Jude"},
        {"id": "REV", "name": "Revelation", "abbreviation": "Rev"},
    ]
    return {"data": books}


@app.get("/api/bibles/{bible_id}/books/{book_id}/chapters")
async def get_book_chapters(bible_id: str, book_id: str, api_key: str = Depends(verify_api_key)):
    """Get list of chapters for a book."""
    # Chapter counts for each book (standard Protestant canon)
    chapter_counts = {
        "GEN": 50, "EXO": 40, "LEV": 27, "NUM": 36, "DEU": 34,
        "JOS": 24, "JDG": 21, "RUT": 4, "1SA": 31, "2SA": 24,
        "1KI": 22, "2KI": 25, "1CH": 29, "2CH": 36, "EZR": 10,
        "NEH": 13, "EST": 10, "JOB": 42, "PSA": 150, "PRO": 31,
        "ECC": 12, "SNG": 8, "ISA": 66, "JER": 52, "LAM": 5,
        "EZK": 48, "DAN": 12, "HOS": 14, "JOL": 3, "AMO": 9,
        "OBA": 1, "JON": 4, "MIC": 7, "NAM": 3, "NAH": 3, "HAB": 3,
        "ZEP": 3, "HAG": 2, "ZEC": 14, "MAL": 4,
        "MAT": 28, "MRK": 16, "LUK": 24, "JHN": 21, "ACT": 28,
        "ROM": 16, "1CO": 16, "2CO": 13, "GAL": 6, "EPH": 6,
        "PHP": 4, "COL": 4, "1TH": 5, "2TH": 3, "1TI": 6,
        "2TI": 4, "TIT": 3, "PHM": 1, "HEB": 13, "JAS": 5,
        "1PE": 5, "2PE": 3, "1JN": 5, "2JN": 1, "3JN": 1,
        "JUD": 1, "REV": 22
    }

    count = chapter_counts.get(book_id.upper(), 0)
    if count == 0:
        raise HTTPException(status_code=404, detail=f"Book {book_id} not found")

    chapters = [
        {"id": f"{book_id}.{i}", "number": str(i), "bookId": book_id}
        for i in range(1, count + 1)
    ]
    return {"data": chapters}


@app.get("/api/bibles/{bible_id}/search")
async def search_bible(
    bible_id: str,
    query: str,
    limit: int = 50,
    offset: int = 0,
    api_key: str = Depends(verify_api_key)
):
    """
    Search verses by keyword (uses Oracle semantic search).
    """
    if not oracle:
        raise HTTPException(status_code=503, detail="Oracle not initialized")

    try:
        # Use Oracle semantic search first
        results = oracle.retrieve_verses(query, k=min(limit, 50))

        # If Oracle has no indexed content yet, fall back to local translation-file keyword search
        if not results:
            translation_hint = "KJV"
            translation_match = re.match(r'^([A-Za-z]{2,6})(?:[-_].*)?$', bible_id or '')
            if translation_match:
                candidate = translation_match.group(1).upper()
                if candidate in SUPPORTED_TRANSLATION_CODES:
                    translation_hint = candidate

            collected = []
            seen_refs = set()
            terms = expand_search_terms(query)
            if not terms:
                terms = [query]

            for term in terms:
                term_matches = search_verses_in_translation_file(term, translation_hint, limit=min(limit, 50), offset=0)
                for item in term_matches:
                    ref = item.get('reference')
                    if not ref or ref in seen_refs:
                        continue
                    seen_refs.add(ref)
                    collected.append(item)
                    if len(collected) >= min(limit, 50):
                        break
                if len(collected) >= min(limit, 50):
                    break

            fallback_matches = collected[offset:offset + limit]

            verses = []
            for idx, result in enumerate(fallback_matches):
                reference = result.get('reference', 'Unknown')
                book_id = reference.split()[0].upper() if reference else 'UNK'
                verses.append({
                    "id": f"verse_fallback_{idx}",
                    "reference": reference,
                    "text": result.get('text', ''),
                    "bookId": book_id
                })

            return {
                "data": {
                    "query": query,
                    "total": len(verses),
                    "verses": verses
                }
            }

        verses = []
        for idx, result in enumerate(results[offset:offset+limit]):
            verses.append({
                "id": f"verse_{idx}",
                "reference": result.get('reference', 'Unknown'),
                "text": result.get('text', ''),
                "bookId": result.get('reference', '').split()[0].upper() if result.get('reference') else 'UNK'
            })

        return {
            "data": {
                "query": query,
                "total": len(results),
                "verses": verses
            }
        }
    except Exception as e:
        logger.error(f"Search error: {e}")
        raise HTTPException(status_code=500, detail=str(e))


if __name__ == "__main__":
    import uvicorn
    import os

    # Try Auto SSL from cPanel first
    ssl_cert = "/home/galileetees/ssl/certs/www_apis_pikzulstudios_com_d4e7e_e0c3f_1776135428_e220d84c8fba0b1efc0d9e4251d9664c.crt"
    ssl_key = "/home/galileetees/ssl/keys/d4e7e_e0c3f_1ab605f99121430f3566d212d96760c3.key"

    # Fallback to self-signed if Auto SSL not available
    if not os.path.exists(ssl_cert) or not os.path.exists(ssl_key):
        base_dir = os.path.dirname(os.path.abspath(__file__))
        ssl_cert = os.path.join(base_dir, "server.crt")
        ssl_key = os.path.join(base_dir, "server.key")

    # Start with HTTPS
    uvicorn.run(
        app,
        host="0.0.0.0",
        port=8002,
        ssl_certfile=ssl_cert,
        ssl_keyfile=ssl_key,
        workers=2
    )
