"""
بارگذاری تنظیمات RAG از rag_config.yaml — با پشتیبانی از چند provider،
چند پایگاه دانش و چند سرویس.
"""
import os
from dataclasses import dataclass, field
from pathlib import Path
from typing import Any

import yaml


@dataclass
class EmbeddingConfig:
    provider: str
    model: str
    batch_size: int = 32
    api_key: str | None = None
    api_key_env: str | None = None
    base_url: str | None = None
    avalai_api_key: str | None = None
    avalai_base_url: str | None = None
    avalai_api_key_env: str | None = None
    arvancloud_api_key: str | None = None
    arvancloud_base_url: str | None = None
    arvancloud_api_key_env: str | None = None


@dataclass
class QdrantConfig:
    host: str = "localhost"
    port: int = 6333
    collection_name: str = "croplogic_kb"
    vector_size: int = 384


@dataclass
class ChunkingConfig:
    max_chunk_tokens: int = 500
    overlap_tokens: int = 50


@dataclass
class LLMConfig:
    provider: str = "gapgpt"
    model: str = "gpt-4o"
    base_url: str | None = None
    api_key_env: str | None = None
    avalai_base_url: str | None = None
    avalai_api_key_env: str | None = None


@dataclass
class KnowledgeBaseConfig:
    path: str
    tone_file: str
    description: str = ""


@dataclass
class ServiceConfig:
    service_id: str
    knowledge_base: str
    llm: LLMConfig = field(default_factory=LLMConfig)
    tone_file: str | None = None
    system_prompt: str | None = None
    use_user_embeddings: bool = True
    description: str = ""


@dataclass
class RAGConfig:
    embedding: EmbeddingConfig
    qdrant: QdrantConfig
    chunking: ChunkingConfig
    llm: LLMConfig = field(default_factory=LLMConfig)
    knowledge_bases: dict[str, KnowledgeBaseConfig] = field(default_factory=dict)
    services: dict[str, ServiceConfig] = field(default_factory=dict)
    chromadb: dict[str, Any] = field(default_factory=dict)


def _build_llm_config(data: dict[str, Any] | None, default: LLMConfig | None = None) -> LLMConfig:
    llm_data = data or {}
    fallback = default or LLMConfig()
    return LLMConfig(
        provider=llm_data.get("provider", fallback.provider),
        model=llm_data.get("model", fallback.model),
        base_url=llm_data.get("base_url", fallback.base_url),
        api_key_env=llm_data.get("api_key_env", fallback.api_key_env),
        avalai_base_url=llm_data.get("avalai_base_url", fallback.avalai_base_url),
        avalai_api_key_env=llm_data.get("avalai_api_key_env", fallback.avalai_api_key_env),
    )


def get_service_config(service_id: str, config: RAGConfig | None = None) -> ServiceConfig:
    cfg = config or load_rag_config()
    service = cfg.services.get(service_id)
    if service is None:
        raise KeyError(f"Unknown service_id: {service_id}")
    return service


def load_rag_config(config_path: str | Path | None = None) -> RAGConfig:
    """
    بارگذاری تنظیمات از YAML و env.
    QDRANT_HOST و QDRANT_PORT از متغیرهای محیطی override می‌شوند.
    """
    if config_path is None:
        base = Path(__file__).resolve().parent.parent
        config_path = base / "config" / "rag_config.yaml"

    path = Path(config_path)
    if not path.exists():
        raise FileNotFoundError(f"RAG config not found: {path}")

    with open(path, encoding="utf-8") as f:
        data = yaml.safe_load(f) or {}

    emb = data.get("embedding", {})
    embedding = EmbeddingConfig(
        provider=emb.get("provider", "sentence_transformers"),
        model=emb.get("model", "text-embedding-3-small"),
        batch_size=emb.get("batch_size", 32),
        api_key=emb.get("api_key"),
        api_key_env=emb.get("api_key_env"),
        base_url=emb.get("base_url"),
        avalai_api_key=emb.get("avalai_api_key"),
        avalai_base_url=emb.get("avalai_base_url"),
        avalai_api_key_env=emb.get("avalai_api_key_env"),
        arvancloud_api_key=emb.get("arvancloud_api_key"),
        arvancloud_base_url=emb.get("arvancloud_base_url"),
        arvancloud_api_key_env=emb.get("arvancloud_api_key_env"),
    )

    qd = data.get("qdrant", {})
    qdrant = QdrantConfig(
        host=os.environ.get("QDRANT_HOST", qd.get("host", "localhost")),
        port=int(os.environ.get("QDRANT_PORT", qd.get("port", 6333))),
        collection_name=qd.get("collection_name", "croplogic_kb"),
        vector_size=qd.get("vector_size", 1536),
    )

    ch = data.get("chunking", {})
    chunking = ChunkingConfig(
        max_chunk_tokens=ch.get("max_chunk_tokens", 500),
        overlap_tokens=ch.get("overlap_tokens", 50),
    )

    llm = _build_llm_config(data.get("llm", {}))

    kb_data = data.get("knowledge_bases", {})
    knowledge_bases: dict[str, KnowledgeBaseConfig] = {}
    for kb_name, kb_conf in kb_data.items():
        knowledge_bases[kb_name] = KnowledgeBaseConfig(
            path=kb_conf.get("path", f"config/knowledge_base/{kb_name}"),
            tone_file=kb_conf.get("tone_file", f"config/tones/{kb_name}_tone.txt"),
            description=kb_conf.get("description", ""),
        )

    services_data = data.get("services", {})
    services: dict[str, ServiceConfig] = {}
    for service_id, service_conf in services_data.items():
        kb_name = service_conf.get("knowledge_base", service_id)
        kb_conf = knowledge_bases.get(kb_name)
        services[service_id] = ServiceConfig(
            service_id=service_id,
            knowledge_base=kb_name,
            llm=_build_llm_config(service_conf.get("llm"), default=llm),
            tone_file=service_conf.get("tone_file") or (kb_conf.tone_file if kb_conf else None),
            system_prompt=service_conf.get("system_prompt"),
            use_user_embeddings=service_conf.get("use_user_embeddings", True),
            description=service_conf.get("description", ""),
        )

    if not services:
        for kb_name, kb_conf in knowledge_bases.items():
            services[kb_name] = ServiceConfig(
                service_id=kb_name,
                knowledge_base=kb_name,
                llm=llm,
                tone_file=kb_conf.tone_file,
                use_user_embeddings=True,
                description=kb_conf.description,
            )

    return RAGConfig(
        embedding=embedding,
        qdrant=qdrant,
        chunking=chunking,
        llm=llm,
        knowledge_bases=knowledge_bases,
        services=services,
        chromadb=data.get("chromadb", {}),
    )
