"""YAML config parsing for RAG knowledge base."""
from __future__ import annotations

from typing import Any, Awaitable, Callable

from logos_adk.errors import ConfigError


VALID_VECTOR_BACKENDS = {"memory", "sqlite", "chroma", "postgres", "postgresql"}
VALID_MODES = {"memory", "tool", "both"}


def load_knowledge_from_config(
    data: Any,
    embed_fn: Callable[[str], Awaitable[list[float]]] | None = None,
) -> dict[str, Any] | None:
    """Parse ``knowledge:`` YAML section.

    Returns a dict with keys: ``knowledge_base``, ``mode``, ``limit``
    or None if no knowledge config is present.
    """
    if data is None:
        return None

    if not isinstance(data, dict):
        raise ConfigError("knowledge config must be a mapping")

    # Vector store backend
    backend_name = _normalize_vector_backend(data.get("backend", "memory"))
    if backend_name not in VALID_VECTOR_BACKENDS:
        valid = ", ".join(sorted(VALID_VECTOR_BACKENDS))
        raise ConfigError(
            f"Unknown knowledge backend: {backend_name}. Valid: {valid}"
        )

    store = _create_vector_store(backend_name, data)

    # Mode
    mode = data.get("mode", "memory")
    if mode not in VALID_MODES:
        valid = ", ".join(sorted(VALID_MODES))
        raise ConfigError(f"Unknown knowledge mode: {mode}. Valid: {valid}")

    # Limit
    limit = data.get("limit", 5)
    if not isinstance(limit, int) or limit <= 0:
        raise ConfigError("knowledge.limit must be a positive integer")

    # Splitter
    splitter = _create_splitter(data.get("splitter"))

    # Embed function
    if embed_fn is None:
        raise ConfigError(
            "Knowledge base requires an embed_fn. "
            "Pass embed_fn when loading config programmatically."
        )

    from logos_adk.rag.knowledge_base import KnowledgeBase

    kb = KnowledgeBase(store=store, embed_fn=embed_fn, splitter=splitter)

    return {"knowledge_base": kb, "mode": mode, "limit": limit}


def _create_vector_store(backend: str, data: dict[str, Any]) -> Any:
    """Create a VectorStore instance from config."""
    if backend == "memory":
        from logos_adk.rag.vector_store import InMemoryVectorStore
        return InMemoryVectorStore()

    if backend == "sqlite":
        path = data.get("path")
        if not path:
            raise ConfigError("knowledge backend 'sqlite' requires 'path'")
        from logos_adk.rag.vector_sqlite import SQLiteVectorStore
        return SQLiteVectorStore(path)

    if backend == "postgresql":
        from logos_adk.rag.vector_postgresql import PostgreSQLVectorStore
        try:
            return PostgreSQLVectorStore(
                data.get("dsn"),
                table_name=data.get("table_name", "rag_chunks"),
            )
        except ValueError as exc:
            raise ConfigError(str(exc)) from exc

    if backend == "chroma":
        from logos_adk.rag.vector_chroma import ChromaVectorStore
        return ChromaVectorStore(
            collection_name=data.get("collection", "logos_rag"),
            path=data.get("path"),
        )

    raise ConfigError(f"Unknown vector backend: {backend}")


def _normalize_vector_backend(backend: Any) -> str:
    if backend == "postgres":
        return "postgresql"
    if not isinstance(backend, str):
        return "memory"
    return backend


def _create_splitter(data: Any) -> Any:
    """Create a TextSplitter from config data."""
    if data is None:
        return None

    if not isinstance(data, dict):
        raise ConfigError("knowledge.splitter must be a mapping")

    from logos_adk.rag.splitter import RecursiveCharacterSplitter

    return RecursiveCharacterSplitter(
        chunk_size=data.get("chunk_size", 1000),
        chunk_overlap=data.get("chunk_overlap", 200),
        separators=data.get("separators"),
    )
