"""LanceDB database connection and operations."""

import contextlib
from pathlib import Path
from typing import Any

import lancedb
from lancedb.table import Table

from .schemas import ChapterRecord, EntityRecord, RelationRecord

CHAPTERS_TABLE = "chapters"
ENTITIES_TABLE = "entities"
RELATIONS_TABLE = "relations"


class Database:
    """LanceDB database wrapper for Echoes."""

    def __init__(self, db_path: str | Path) -> None:
        self.db_path = Path(db_path)
        self._db: lancedb.DBConnection | None = None

    @property
    def db(self) -> lancedb.DBConnection:
        """Lazy connection to LanceDB."""
        if self._db is None:
            self._db = lancedb.connect(self.db_path)
        return self._db

    def _get_or_create_table(self, name: str, schema: type) -> Table:
        """Get existing table or create new one with schema."""
        existing = self.db.list_tables().tables
        if name in existing:
            return self.db.open_table(name)
        return self.db.create_table(name, schema=schema)

    @property
    def chapters(self) -> Table:
        """Chapters table."""
        return self._get_or_create_table(CHAPTERS_TABLE, ChapterRecord)

    @property
    def entities(self) -> Table:
        """Entities table."""
        return self._get_or_create_table(ENTITIES_TABLE, EntityRecord)

    @property
    def relations(self) -> Table:
        """Relations table."""
        return self._get_or_create_table(RELATIONS_TABLE, RelationRecord)

    def upsert_chapters(self, records: list[dict[str, Any]]) -> int:
        """Insert or update chapters. Returns count."""
        if not records:
            return 0
        ids = [r["id"] for r in records]
        with contextlib.suppress(Exception):
            self.chapters.delete(f"id IN {tuple(ids)}" if len(ids) > 1 else f"id = '{ids[0]}'")
        self.chapters.add(records)
        return len(records)

    def upsert_entities(self, records: list[dict[str, Any]]) -> int:
        """Insert or update entities. Returns count."""
        if not records:
            return 0
        ids = [r["id"] for r in records]
        with contextlib.suppress(Exception):
            self.entities.delete(f"id IN {tuple(ids)}" if len(ids) > 1 else f"id = '{ids[0]}'")
        self.entities.add(records)
        return len(records)

    def upsert_relations(self, records: list[dict[str, Any]]) -> int:
        """Insert or update relations. Returns count."""
        if not records:
            return 0
        ids = [r["id"] for r in records]
        with contextlib.suppress(Exception):
            self.relations.delete(f"id IN {tuple(ids)}" if len(ids) > 1 else f"id = '{ids[0]}'")
        self.relations.add(records)
        return len(records)

    def get_chapter_hashes(self) -> dict[str, str]:
        """Get all chapter file_path -> file_hash mappings."""
        try:
            results = (
                self.chapters.search().select(["file_path", "file_hash"]).limit(10000).to_list()
            )
            return {r["file_path"]: r["file_hash"] for r in results}
        except Exception:
            return {}

    def delete_chapters_by_paths(self, paths: list[str]) -> int:
        """Delete chapters by file paths. Returns count."""
        if not paths:
            return 0
        try:
            filter_expr = (
                f"file_path IN {tuple(paths)}" if len(paths) > 1 else f"file_path = '{paths[0]}'"
            )
            self.chapters.delete(filter_expr)
            return len(paths)
        except Exception:
            return 0

    def close(self) -> None:
        """Close database connection."""
        self._db = None
