"""
openbible.info cross-reference loader and lookup.

Data derived from the calebmpeterson/bible-cross-reference-json dataset,
which is in turn based on openbible.info's ~340,000 cross-reference pairs.

The core data file (data/openbible_xrefs.json) is a JSON dict mapping
canonical verse references to lists of cross-referenced verse references.

Reference format: "OSIS chapter:verse" (e.g. "Gen 1:1", "John 3:16").

Data license: CC-BY-SA 4.0 (inherited from calebmpeterson / openbible.info).
"""

from __future__ import annotations

import json
import logging
from pathlib import Path
from typing import Dict, List

logger = logging.getLogger(__name__)

# Module-level cache
_xref_index: Dict[str, List[str]] | None = None
_load_attempted: bool = False


def _data_path() -> Path:
    """Return the path to the cross-reference JSON data file."""
    # Resolve relative to this module's location
    module_dir = Path(__file__).resolve().parent.parent
    return module_dir / "data" / "openbible_xrefs.json"


def _load_index() -> Dict[str, List[str]]:
    """Load the cross-reference index from disk (cached)."""
    global _xref_index, _load_attempted

    if _xref_index is not None:
        return _xref_index

    if _load_attempted:
        return {}

    _load_attempted = True
    path = _data_path()

    if not path.exists():
        logger.warning("openbible_xrefs data file not found: %s", path)
        logger.warning("Build it with: python3 scripts/build_openbible_xrefs.py")
        _xref_index = {}
        return _xref_index

    try:
        with open(path, "r", encoding="utf-8") as f:
            _xref_index = json.load(f)
        logger.info(
            "Loaded %d cross-reference entries from %s",
            len(_xref_index),
            path,
        )
    except (json.JSONDecodeError, OSError) as e:
        logger.error("Failed to load openbible_xrefs data: %s", e)
        _xref_index = {}

    return _xref_index


def canonical_ref(book_osis: str, chapter: int, verse: int) -> str:
    """Format a verse reference in canonical key format."""
    return f"{book_osis} {chapter}:{verse}"


def lookup(reference: str) -> List[str]:
    """Look up cross-references for a Bible verse reference.

    Uses the project's reference parser (accordance_parser.canon.parse_reference)
    to parse the input, then looks up matching cross-references in the
    openbible.info dataset.

    Args:
        reference: A Bible reference string (e.g. 'Genesis 1:1', 'John 3:16').

    Returns:
        List of canonical reference strings (e.g. ['Exod 20:11', ...]).
        Returns empty list if no cross-references found or reference unparseable.
    """
    try:
        from accordance_parser.canon import parse_reference
    except ImportError:
        logger.error("Cannot import accordance_parser.canon")
        return []

    result = parse_reference(reference)
    if result is None or result.verse is None:
        return []

    key = canonical_ref(result.book_osis, result.chapter, result.verse)
    index = _load_index()
    return index.get(key, [])


def lookup_formatted(reference: str, max_results: int = 50) -> List[Dict[str, object]]:
    """Look up cross-references and return structured results.

    Args:
        reference: A Bible reference string.
        max_results: Maximum number of results to return.

    Returns:
        List of dicts with {reference, book, chapter, verse} keys.
    """
    refs = lookup(reference)
    results: List[Dict[str, object]] = []
    for ref_str in refs[:max_results]:
        parts = ref_str.split()
        if len(parts) < 2:
            continue
        book = parts[0]
        ch_vs = parts[1].split(":")
        if len(ch_vs) != 2:
            continue
        try:
            chapter = int(ch_vs[0])
            verse = int(ch_vs[1])
        except ValueError:
            continue
        results.append(
            {
                "reference": ref_str,
                "book": book,
                "chapter": chapter,
                "verse": verse,
            }
        )
    return results


def search_xrefs(
    reference: str,
    max_results: int = 30,
) -> List[Dict[str, object]]:
    """Search for cross-references, returning structured results.

    Compatible with the search_all() / find_cross_references() result format.
    """
    return lookup_formatted(reference, max_results)


def verse_count() -> int:
    """Return the number of verses in the cross-reference index."""
    index = _load_index()
    return len(index)


def pair_count() -> int:
    """Return the total number of cross-reference pairs in the index."""
    index = _load_index()
    return sum(len(refs) for refs in index.values())


def is_available() -> bool:
    """Return True if the cross-reference data is loaded and available."""
    index = _load_index()
    return len(index) > 0


# ---------------------------------------------------------------------------
# MCP tool registration helper
# ---------------------------------------------------------------------------


def register_mcp_tools(mcp: object) -> None:
    """Register openbible cross-reference tools on an MCP server instance.

    Args:
        mcp: A FastMCP instance.
    """

    @mcp.tool()  # type: ignore[attr-defined]
    def lookup_openbible_crossrefs(
        reference: str,
        max_results: int = 30,
    ) -> str:
        """Look up openbible.info cross-references for a Bible verse.

        Powered by the openbible.info cross-reference dataset (~340,000
        voted and ranked verse pairs, CC-BY-SA 4.0).  Returns verses
        that share themes, words, events, or people with the given verse.

        Args:
            reference:   Book chapter:verse (e.g. 'Genesis 1:1', 'John 3:16').
            max_results: Maximum cross-references to return (default 30).

        Returns:
            Markdown-formatted list of related verses with book names.
        """
        from accordance_parser.canon import BOOKS_BY_OSIS, parse_reference

        xrefs = lookup(reference)

        if not xrefs:
            parsed = parse_reference(reference)
            if parsed is None:
                return f"Could not parse reference '{reference}'. Use format like 'Genesis 1:1' or 'John 3:16'."
            return f"No openbible.info cross-references found for '{reference}'."

        # Resolve OSIS codes to full book names for display
        book_names: dict[str, str] = {}
        for ref_str in xrefs[:max_results]:
            osis = ref_str.split()[0]
            if osis not in book_names:
                book = BOOKS_BY_OSIS.get(osis)
                book_names[osis] = book.name if book else osis

        lines = [f"# OpenBible Cross-References: {reference}", ""]
        lines.append(
            f"**{min(len(xrefs), max_results)} of {len(xrefs)} total "
            f"cross-references** (source: openbible.info, CC-BY-SA 4.0)"
        )
        lines.append("")

        for i, ref_str in enumerate(xrefs[:max_results], 1):
            osis = ref_str.split()[0]
            book_name = book_names.get(osis, osis)
            ch_vs = ref_str.split()[1] if " " in ref_str else ""
            display = f"{book_name} {ch_vs}" if ch_vs else ref_str
            lines.append(f"{i}. {display}  ")
            lines.append(f"   `{ref_str}`")

        if len(xrefs) > max_results:
            lines.append(
                f"\n...and {len(xrefs) - max_results} more "
                f"(increase max_results to see them)."
            )

        return "\n".join(lines)


__all__ = [
    "lookup",
    "lookup_formatted",
    "search_xrefs",
    "verse_count",
    "pair_count",
    "is_available",
    "canonical_ref",
    "register_mcp_tools",
]
