"""KB 设置模型 — 检索模式默认/命中处理默认/授权用户/caching/rerank。

KB 级别设置控制检索与命中处理的默认行为，Agent 运行时可通过
``RetrievalRequest`` 字段覆盖。

当前为进程内 dict 存储（重启丢失）。
ponytail: 升级路径 — 迁移到 PG（KBModel 已有 default_query_mode /
default_hit_processing / caching_disabled 列），rerank 相关设置需新增
JSON 列或独立表。
"""

from __future__ import annotations

import logging

from pydantic import BaseModel, ConfigDict

from agentkit.rag_platform.models import QueryMode

logger = logging.getLogger(__name__)

HIT_PROCESSING_MODEL_OPT = "model_opt"
HIT_PROCESSING_DIRECT = "direct"


class KBSettings(BaseModel):
    """KB 级别设置 — 可通过 API 修改。

    owner 字段用于 ACL 校验：仅 owner（或 admin）可修改设置，viewer 只读。
    """

    model_config = ConfigDict()

    kb_id: str
    owner: str | None = None  # KB 所有者（仅 owner 可修改设置）
    default_query_mode: QueryMode = QueryMode.blend
    default_hit_processing: str = HIT_PROCESSING_MODEL_OPT  # model_opt | direct
    caching_disabled: bool = False
    rerank_enabled: bool = True
    rerank_provider: str = "cohere"  # cohere | bge | none
    rerank_api_key: str | None = None
    rerank_base_url: str | None = None
    data_export_warning: bool = False  # True = 使用云端 rerank 处理敏感数据


class KBSettingsUpdate(BaseModel):
    """KB 设置更新请求 — 仅 owner 可修改。

    所有字段可选（部分更新语义），None 表示不更新该字段。
    """

    model_config = ConfigDict()

    default_query_mode: QueryMode | None = None
    default_hit_processing: str | None = None
    caching_disabled: bool | None = None
    rerank_enabled: bool | None = None
    rerank_provider: str | None = None
    rerank_api_key: str | None = None
    rerank_base_url: str | None = None


class KBSettingsStore:
    """KB 设置存储 — 读写 KB 设置。

    当前为进程内 dict 存储。CRUD 方法为 async 以保持与未来 PG 迁移的接口兼容。
    """

    def __init__(self) -> None:
        self._settings: dict[str, KBSettings] = {}

    async def get_settings(self, kb_id: str) -> KBSettings | None:
        """读取 KB 设置。不存在时返回 None。"""
        return self._settings.get(kb_id)

    async def get_or_create(self, kb_id: str, owner: str | None = None) -> KBSettings:
        """读取 KB 设置，不存在时创建默认设置。

        已存在时不覆盖 owner。
        """
        if kb_id not in self._settings:
            self._settings[kb_id] = KBSettings(kb_id=kb_id, owner=owner)
        return self._settings[kb_id]

    async def update_settings(
        self,
        kb_id: str,
        update: KBSettingsUpdate,
        owner: str | None = None,
    ) -> KBSettings:
        """更新 KB 设置 — 仅更新非 None 字段。

        首次更新时若提供 owner 则设置所有者。owner 校验由路由层完成。
        """
        existing = self._settings.get(kb_id)
        if existing is None:
            existing = KBSettings(kb_id=kb_id, owner=owner)
            self._settings[kb_id] = existing

        update_data = update.model_dump(exclude_none=True)
        updated = existing.model_copy(update=update_data)
        self._settings[kb_id] = updated
        return updated

    def is_owner(self, kb_id: str, user_id: str | None) -> bool:
        """检查用户是否为 KB 所有者。KB 不存在或 owner 未设置时返回 False。"""
        settings = self._settings.get(kb_id)
        if settings is None or settings.owner is None:
            return False
        return settings.owner == user_id

    def set_owner(self, kb_id: str, owner: str) -> bool:
        """设置 KB 所有者。返回 True 如果 KB 存在。"""
        settings = self._settings.get(kb_id)
        if settings is None:
            return False
        self._settings[kb_id] = settings.model_copy(update={"owner": owner})
        return True


# 模块级单例 — 类似 KnowledgeSourceStore 模式
_settings_store = KBSettingsStore()


def get_settings_store() -> KBSettingsStore:
    """返回进程级 KBSettingsStore 单例。"""
    return _settings_store


def set_settings_store(store: KBSettingsStore) -> None:
    """注入自定义 KBSettingsStore（测试用）。"""
    global _settings_store
    _settings_store = store


__all__ = [
    "HIT_PROCESSING_DIRECT",
    "HIT_PROCESSING_MODEL_OPT",
    "KBSettings",
    "KBSettingsStore",
    "KBSettingsUpdate",
    "get_settings_store",
    "set_settings_store",
]
