"""Snippet library — save, search, and manage favorite AI responses."""

from __future__ import annotations

import logging
import os
import threading
import time
import uuid
from typing import TypedDict, cast

from .utils.atomic_io import atomic_write_json, safe_load_json

log = logging.getLogger(__name__)


class Snippet(TypedDict):
    id: str
    title: str
    text: str
    tags: list[str]
    created_at: str
    timestamp: float


class SnippetManager:
    """Persistent snippet library for saving favorite AI responses."""

    def __init__(self, data_dir: str | None = None) -> None:
        self._data_dir: str = data_dir or os.path.expanduser("~/.muravey-china/snippets")
        self._lock: threading.Lock = threading.Lock()
        self._snippets: list[Snippet] = []
        self._load()

    def save_snippet(self, text: str, title: str = "", tags: list[str] | None = None) -> Snippet:
        snippet: Snippet = {
            "id": uuid.uuid4().hex[:8],
            "title": title or text[:50].strip(),
            "text": text,
            "tags": tags or [],
            "created_at": time.strftime("%Y-%m-%d %H:%M:%S"),
            "timestamp": time.time(),
        }
        with self._lock:
            self._snippets.append(snippet)
            self._persist()
        log.info("Snippet saved: %s", snippet["id"])
        return snippet

    def delete_snippet(self, snippet_id: str) -> bool:
        with self._lock:
            for i, s in enumerate(self._snippets):
                if s["id"] == snippet_id:
                    self._snippets.pop(i)
                    self._persist()
                    log.info("Snippet deleted: %s", snippet_id)
                    return True
        return False

    def list_snippets(self, limit: int = 50) -> list[Snippet]:
        with self._lock:
            return sorted(self._snippets, key=lambda s: s.get("timestamp", 0.0), reverse=True)[
                :limit
            ]

    def search(self, query: str) -> list[Snippet]:
        q = query.lower()
        with self._lock:
            results: list[Snippet] = []
            for s in self._snippets:
                if (
                    q in s.get("title", "").lower()
                    or q in s.get("text", "").lower()
                    or any(q in t.lower() for t in s.get("tags", []))
                ):
                    results.append(s)
            return sorted(results, key=lambda s: s.get("timestamp", 0.0), reverse=True)

    @property
    def count(self) -> int:
        with self._lock:
            return len(self._snippets)

    def get_by_id(self, snippet_id: str) -> Snippet | None:
        with self._lock:
            for s in self._snippets:
                if s["id"] == snippet_id:
                    return s
        return None

    def _persist(self) -> None:
        path = os.path.join(self._data_dir, "snippets.json")
        try:
            atomic_write_json(path, self._snippets)
        except OSError as e:
            log.warning("Failed to save snippets: %s", e)

    def _load(self) -> None:
        path = os.path.join(self._data_dir, "snippets.json")
        data = safe_load_json(path, default=[])
        self._snippets = cast(list[Snippet], data)
        log.info("Loaded %d snippets", len(self._snippets))
