"""Document indexer – chunk text and generate embeddings for storage."""

from __future__ import annotations

import hashlib
import time
import uuid
from typing import Any, Callable

from thryve.core.memory.storage import SQLiteStorage
from thryve.core.memory.types import MemoryChunk
from thryve.utils import get_logger

logger = get_logger("memory.indexer")


class MemoryIndexer:
    """Chunk and index documents into the memory storage.

    The indexer deduplicates by content hash so the same text is never stored
    twice.
    """

    def __init__(
        self,
        storage: SQLiteStorage,
        embedding_fn: Callable[[list[str]], list[list[float]]] | None = None,
        chunk_size: int = 512,
        chunk_overlap: int = 64,
    ) -> None:
        self._storage = storage
        self._embedding_fn = embedding_fn
        self._chunk_size = chunk_size
        self._chunk_overlap = chunk_overlap

    def index_text(
        self,
        text: str,
        source: str = "short_term",
        metadata: dict[str, Any] | None = None,
    ) -> list[MemoryChunk]:
        """Split *text* into chunks, compute embeddings, and store."""
        chunks_text = self._split(text)
        embeddings: list[list[float] | None] = [None] * len(chunks_text)

        if self._embedding_fn is not None:
            try:
                embeddings = self._embedding_fn(chunks_text)  # type: ignore[assignment]
            except Exception:
                logger.warning("Embedding generation failed; storing without embeddings")

        now = time.time()
        stored: list[MemoryChunk] = []
        for i, ct in enumerate(chunks_text):
            chunk = MemoryChunk(
                id=uuid.uuid4().hex,
                text=ct,
                source=source,
                created_at=now,
                hash=hashlib.sha256(ct.encode()).hexdigest()[:16],
                metadata=metadata or {},
                embedding=embeddings[i] if embeddings[i] is not None else None,
            )
            self._storage.insert(chunk)
            stored.append(chunk)

        return stored

    # ------------------------------------------------------------------
    # Text splitting
    # ------------------------------------------------------------------

    def _split(self, text: str) -> list[str]:
        """Naive character-level chunking with overlap."""
        if len(text) <= self._chunk_size:
            return [text]
        chunks: list[str] = []
        start = 0
        while start < len(text):
            end = start + self._chunk_size
            chunks.append(text[start:end])
            start = end - self._chunk_overlap
        return chunks
