"""
mcp_server/persistence/db.py — SQLite persistence for analysis cache.

Stores completed lens analyses and syntheses across sessions.
Initialized via FastMCP lifespan context.
"""

from __future__ import annotations

import json
import sqlite3
from pathlib import Path
from typing import Optional


def init_db(db_path: str | Path) -> sqlite3.Connection:
    """Create/open the SQLite database and ensure tables exist."""
    db_path = Path(db_path)
    db_path.parent.mkdir(parents=True, exist_ok=True)

    db = sqlite3.connect(str(db_path))
    db.execute("PRAGMA journal_mode=WAL")
    db.execute("PRAGMA foreign_keys=ON")

    db.executescript("""
        CREATE TABLE IF NOT EXISTS analyses (
            text_id     TEXT    NOT NULL,
            lens        TEXT    NOT NULL,
            model       TEXT    NOT NULL,
            result_json TEXT    NOT NULL,
            created_at  TEXT    NOT NULL DEFAULT (datetime('now')),
            PRIMARY KEY (text_id, lens)
        );

        CREATE TABLE IF NOT EXISTS syntheses (
            text_id     TEXT    NOT NULL PRIMARY KEY,
            lenses_json TEXT    NOT NULL,
            result_json TEXT    NOT NULL,
            model       TEXT    NOT NULL,
            created_at  TEXT    NOT NULL DEFAULT (datetime('now'))
        );

        CREATE TABLE IF NOT EXISTS comparisons (
            comparison_id TEXT  NOT NULL PRIMARY KEY,
            text_ids_json TEXT  NOT NULL,
            lens          TEXT  NOT NULL,
            result_json   TEXT  NOT NULL,
            model         TEXT  NOT NULL,
            created_at    TEXT  NOT NULL DEFAULT (datetime('now'))
        );
    """)
    db.commit()
    return db


def save_analysis(db: sqlite3.Connection, text_id: str, lens: str,
                  model: str, result_json: str) -> None:
    """Insert or replace a lens analysis result."""
    db.execute(
        "INSERT OR REPLACE INTO analyses (text_id, lens, model, result_json) "
        "VALUES (?, ?, ?, ?)",
        (text_id, lens, model, result_json),
    )
    db.commit()


def load_analysis(db: sqlite3.Connection, text_id: str,
                  lens: str) -> Optional[str]:
    """Load a cached analysis result. Returns JSON string or None."""
    row = db.execute(
        "SELECT result_json FROM analyses WHERE text_id = ? AND lens = ?",
        (text_id, lens),
    ).fetchone()
    return row[0] if row else None


def list_analyses_for_text(db: sqlite3.Connection,
                           text_id: str) -> list[str]:
    """Return list of lens names that have cached analyses for a text."""
    rows = db.execute(
        "SELECT lens FROM analyses WHERE text_id = ? ORDER BY lens",
        (text_id,),
    ).fetchall()
    return [r[0] for r in rows]


def load_all_analyses_for_text(db: sqlite3.Connection,
                               text_id: str) -> dict[str, str]:
    """Return {lens: result_json} for all analyses of a text."""
    rows = db.execute(
        "SELECT lens, result_json FROM analyses WHERE text_id = ?",
        (text_id,),
    ).fetchall()
    return {r[0]: r[1] for r in rows}


def save_synthesis(db: sqlite3.Connection, text_id: str,
                   lenses: list[str], model: str, result_json: str) -> None:
    """Insert or replace a synthesis result."""
    db.execute(
        "INSERT OR REPLACE INTO syntheses "
        "(text_id, lenses_json, model, result_json) VALUES (?, ?, ?, ?)",
        (text_id, json.dumps(lenses), model, result_json),
    )
    db.commit()


def load_synthesis(db: sqlite3.Connection,
                   text_id: str) -> Optional[str]:
    """Load a cached synthesis result. Returns JSON string or None."""
    row = db.execute(
        "SELECT result_json FROM syntheses WHERE text_id = ?",
        (text_id,),
    ).fetchone()
    return row[0] if row else None


def count_cached_analyses(db: sqlite3.Connection) -> int:
    """Total number of cached analyses across all texts."""
    row = db.execute("SELECT COUNT(*) FROM analyses").fetchone()
    return row[0]


def search_analyses(db: sqlite3.Connection, query: str,
                    lens: Optional[str] = None) -> list[dict]:
    """Search cached analyses by text content in result_json.

    Returns list of {text_id, lens, snippet} dicts.
    """
    params: list = [f"%{query}%"]
    sql = "SELECT text_id, lens, result_json FROM analyses WHERE result_json LIKE ?"
    if lens:
        sql += " AND lens = ?"
        params.append(lens)
    sql += " ORDER BY created_at DESC LIMIT 20"

    rows = db.execute(sql, params).fetchall()
    results = []
    for text_id, lens_name, rj in rows:
        # Extract a short snippet around the match
        lower = rj.lower()
        idx = lower.find(query.lower())
        start = max(0, idx - 80)
        end = min(len(rj), idx + len(query) + 80)
        snippet = rj[start:end]
        results.append({
            "text_id": text_id,
            "lens": lens_name,
            "snippet": f"...{snippet}...",
        })
    return results
