"""Search and Q&A data access functions."""
from __future__ import annotations

import re
from typing import TypedDict

from ietf_analyzer.config import Config
from ietf_analyzer.db import Database
from ietf_analyzer.search import HybridSearch


class SearchResults(TypedDict):
    """Global search results from :func:`global_search`."""
    drafts: list[dict]
    ideas: list[dict]
    authors: list[dict]
    gaps: list[dict]

def global_search(db: Database, query: str) -> SearchResults:
    """Search across drafts (FTS5), ideas, authors, and gaps.

    Returns {drafts: [...], ideas: [...], authors: [...], gaps: [...]}.
    """
    results: dict = {"drafts": [], "ideas": [], "authors": [], "gaps": []}
    if not query or not query.strip():
        return results

    q = query.strip()

    # 1. Drafts via FTS5
    try:
        fts_query = re.sub(r'[^\w\s]', '', q)
        fts_query = re.sub(r'\b(NEAR|OR|AND|NOT)\b', '', fts_query, flags=re.IGNORECASE)
        fts_query = re.sub(r'\s+', ' ', fts_query).strip()
        if not fts_query:
            raise ValueError("empty query after sanitization")
        rows = db.conn.execute(
            """SELECT d.name, d.title, d.abstract, d.time, d."group"
            FROM drafts d
            JOIN drafts_fts f ON d.rowid = f.rowid
            WHERE drafts_fts MATCH ?
            ORDER BY rank
            LIMIT 50""",
            (fts_query,),
        ).fetchall()
        for r in rows:
            results["drafts"].append({
                "name": r["name"],
                "title": r["title"],
                "abstract": (r["abstract"] or "")[:200],
                "date": r["time"],
                "group": r["group"] or "individual",
            })
    except Exception:
        # FTS5 match can fail on certain query syntax; fall back to LIKE
        like = f"%{q}%"
        rows = db.conn.execute(
            """SELECT name, title, abstract, time, "group" FROM drafts
            WHERE title LIKE ? OR name LIKE ? OR abstract LIKE ?
            LIMIT 50""",
            (like, like, like),
        ).fetchall()
        for r in rows:
            results["drafts"].append({
                "name": r["name"],
                "title": r["title"],
                "abstract": (r["abstract"] or "")[:200],
                "date": r["time"],
                "group": r["group"] or "individual",
            })

    # 2. Ideas via LIKE
    like = f"%{q}%"
    rows = db.conn.execute(
        """SELECT id, title, description, idea_type, draft_name FROM ideas
        WHERE title LIKE ? OR description LIKE ?
        ORDER BY id LIMIT 50""",
        (like, like),
    ).fetchall()
    for r in rows:
        results["ideas"].append({
            "id": r["id"],
            "title": r["title"],
            "description": (r["description"] or "")[:200],
            "type": r["idea_type"],
            "draft_name": r["draft_name"],
        })

    # 3. Authors via LIKE
    results["authors"] = db.search_authors(q, limit=50)

    # 4. Gaps via LIKE
    results["gaps"] = db.search_gaps(q, limit=50)

    return results

def get_ask_search(db: Database, question: str, top_k: int = 5) -> dict:
    """Search-only (free) — returns sources + cached answer if available."""
    config = Config.load()
    searcher = HybridSearch(config, db)
    return searcher.search_only(question, top_k=top_k)

def get_ask_synthesize(db: Database, question: str, top_k: int = 5, cheap: bool = True) -> dict:
    """Run Claude synthesis (costs tokens, result is cached permanently)."""
    config = Config.load()
    searcher = HybridSearch(config, db)
    return searcher.ask(question, top_k=top_k, cheap=cheap)
