from typing import Any, TypeVar, overload

from pydantic import BaseModel, ValidationError
import ujson as json

from zhenxun.configs.config import Config
from zhenxun.models.group_plugin_setting import GroupPluginSetting
from zhenxun.services.cache import Cache
from zhenxun.services.data_access import DataAccess
from zhenxun.services.log import logger
from zhenxun.utils.pydantic_compat import model_dump, model_validate, parse_as

T = TypeVar("T", bound=BaseModel)


class GroupSettingsService:
    """
    一个用于管理插件分群配置的服务。
    集成了聚合缓存、批量操作和版本迁移功能。
    """

    def __init__(self):
        self.dao = DataAccess(GroupPluginSetting)
        self._cache = Cache[dict]("group_plugin_settings")

    async def set(
        self, group_id: str, plugin_name: str, settings_model: BaseModel
    ) -> None:
        """
        为一个插件在指定群组中设置完整的配置模型。

        参数:
            group_id: 目标群组ID。
            plugin_name: 插件的模块名。
            settings_model: 包含完整配置的Pydantic模型实例。
        """
        settings_dict = model_dump(settings_model)
        json_value = json.dumps(settings_dict, ensure_ascii=False)

        await self.dao.update_or_create(
            defaults={"settings": json_value},  # type: ignore
            group_id=group_id,
            plugin_name=plugin_name,
        )

        await self.dao.clear_cache(group_id=group_id, plugin_name=plugin_name)

    async def set_key_value(
        self, group_id: str, plugin_name: str, key: str, value: Any
    ) -> None:
        """为一个插件在指定群组中设置单个配置项的值。"""
        setting_entry, _ = await GroupPluginSetting.get_or_create(
            defaults={"settings": {}},
            group_id=group_id,
            plugin_name=plugin_name,
        )

        if not isinstance(setting_entry.settings, dict):
            setting_entry.settings = {}

        setting_entry.settings[key] = value
        await setting_entry.save(update_fields=["settings"])
        await self.dao.clear_cache(group_id=group_id, plugin_name=plugin_name)

    async def reset_key(self, group_id: str, plugin_name: str, key: str) -> bool:
        """重置单个配置项"""
        setting = await self.dao.get_or_none(group_id=group_id, plugin_name=plugin_name)
        if setting and isinstance(setting.settings, dict) and key in setting.settings:
            del setting.settings[key]
            if not setting.settings:
                await setting.delete()
            else:
                await setting.save(update_fields=["settings"])
            await self.dao.clear_cache(group_id=group_id, plugin_name=plugin_name)
            return True
        return False

    async def get(
        self, group_id: str, plugin_name: str, key: str, default: Any = None
    ) -> Any:
        """
        获取一个分群配置项的值，如果群组未单独设置，则回退到全局默认值。

        参数:
            group_id: 目标群组ID。
            plugin_name: 插件的模块名。
            key: 配置项的键。
            default: 如果找不到配置项，返回的默认值。

        返回:
            配置项的值。
        """
        full_settings = await self.get_all_for_plugin(group_id, plugin_name)
        return full_settings.get(key, default)

    async def reset_all_for_plugin(self, group_id: str, plugin_name: str) -> bool:
        """
        重置一个插件在指定群组的配置，使其回退到全局默认值。
        这通过删除数据库中的对应记录来实现。

        参数:
            group_id: 目标群组ID。
            plugin_name: 插件的模块名。

        返回:
            bool: 如果成功删除了一个条目，则返回 True，否则返回 False。
        """
        deleted_count = await self.dao.delete(
            group_id=group_id, plugin_name=plugin_name
        )

        if deleted_count > 0:
            await self.dao.clear_cache(group_id=group_id, plugin_name=plugin_name)
            logger.debug(f"已重置插件 '{plugin_name}' 在群组 '{group_id}' 的配置。")
            return True

        return False

    @overload
    async def get_all_for_plugin(
        self, group_id: str, plugin_name: str, *, parse_model: type[T]
    ) -> T: ...

    @overload
    async def get_all_for_plugin(
        self, group_id: str, plugin_name: str, *, parse_model: None = None
    ) -> dict[str, Any]: ...

    async def get_all_for_plugin(
        self, group_id: str, plugin_name: str, *, parse_model: type[T] | None = None
    ) -> T | dict[str, Any]:
        """
        获取一个插件在指定群组中的完整配置，应用了“继承与覆盖”逻辑。
        它首先获取全局默认配置，然后用数据库中存储的群组特定配置覆盖它。

        参数:
            group_id: 目标群组ID。
            plugin_name: 插件的模块名。
            parse_model: (可选) Pydantic模型，用于解析和验证配置。
        """
        cache_key = f"{group_id}:{plugin_name}"
        cached_settings = await self._cache.get(cache_key)
        if cached_settings is not None:
            logger.debug(f"缓存命中: {cache_key}")
            if parse_model:
                try:
                    return parse_as(parse_model, cached_settings)
                except (ValidationError, TypeError) as e:
                    logger.warning(
                        f"缓存数据 '{cache_key}' 与模型 '{parse_model.__name__}' "
                        f"不匹配: {e}。将从数据库重新加载。"
                    )
            else:
                return cached_settings

        logger.debug(f"缓存未命中: {cache_key}，从数据库加载。")

        global_config_group = Config.get(plugin_name)
        final_settings_dict = {
            key: global_config_group.get(key, build_model=False)
            for key in global_config_group.configs.keys()
        }

        group_setting_entry = await self.dao.get_or_none(
            group_id=group_id, plugin_name=plugin_name
        )
        if group_setting_entry:
            try:
                group_specific_settings = group_setting_entry.settings
                if isinstance(group_specific_settings, dict):
                    final_settings_dict.update(group_specific_settings)
                else:
                    logger.warning(
                        f"群组 {group_id} 插件 '{plugin_name}' 的配置格式不正确"
                        f"（不是字典），已忽略。"
                    )
            except Exception as e:
                logger.warning(
                    f"加载群组 {group_id} 插件 '{plugin_name}' 的特定配置时出错: {e}"
                )

        await self._cache.set(cache_key, final_settings_dict)

        if parse_model:
            try:
                return parse_as(parse_model, final_settings_dict)
            except (ValidationError, TypeError) as e:
                logger.warning(
                    f"插件 '{plugin_name}' 的配置无法解析为 '{parse_model.__name__}'。"
                    f"值: {final_settings_dict}, 错误: {e}。将返回一个默认模型实例。"
                )
                return parse_as(parse_model, {})

        return final_settings_dict

    async def set_bulk(
        self, group_ids: list[str], plugin_name: str, key: str, value: Any
    ) -> tuple[int, int]:
        """
        为多个群组批量设置同一个配置项。

        参数:
            group_ids: 目标群组ID列表。
            plugin_name: 插件模块名。
            key: 配置项的键。
            value: 要设置的值。

        返回:
            一个元组 (updated_count, created_count)。
        """
        if not group_ids:
            return 0, 0

        for group_id in group_ids:
            current_settings = await self.get_all_for_plugin(group_id, plugin_name)
            current_settings[key] = value
            await self.set(
                group_id, plugin_name, model_validate(BaseModel, current_settings)
            )
        return len(group_ids), 0


group_settings_service = GroupSettingsService()
