# apps/core/utils/restricted_term_manager.py
from django.core.exceptions import ValidationError


class RestrictedTermManager:
    """
    限制词管理器，负责收集和验证受限词汇。
    支持静态系统词汇和动态模型词汇。
    具体的使用方法可以参考category模型中的clean 、save、delect中相关的使用
    """

    _restricted_terms = set()  # 核心限制词集合
    _is_initialized = False  # 初始化标志，避免重复操作

    @classmethod
    def initialize_core_terms(cls, system_terms=None, custom_terms=None):
        """
        初始化核心限制词（系统保留词和自定义词）。
        通常在应用启动时调用一次。

        参数:
            system_terms: 系统保留词列表，如 ['admin', 'category', 'tags']
            custom_terms: 用户自定义限制词列表
        """
        if system_terms:
            cls.add_restricted_terms(system_terms)
        if custom_terms:
            cls.add_restricted_terms(custom_terms)

        # 可以在这里设置一些绝对不允许使用的核心词汇
        core_terms = ["admin", "api", "static", "media", "category", "tags", "wiki", "article"]
        cls.add_restricted_terms(core_terms)

        cls._is_initialized = True
        # print(f"核心限制词初始化完成。当前词库: {cls._restricted_terms}") # 可选：日志记录

    @classmethod
    def sync_terms_from_model(cls, model_class, slug_field_name="slug"):
        """
        从指定的Django模型同步词汇到限制词集。
        例如，同步所有Category模型的slug值。

        参数:
            model_class: 需要同步的Django模型类（如Category）
            slug_field_name: 模型中包含标识符的字段名，默认为'slug'
        """
        try:
            # 获取模型中所有实例的指定字段值
            existing_terms = model_class.objects.values_list(slug_field_name, flat=True)
            new_terms = set(existing_terms)

            # 计算新增的词汇（避免重复添加）
            terms_to_add = new_terms - cls._restricted_terms
            if terms_to_add:
                cls.add_restricted_terms(terms_to_add)
                # print(f"从模型 {model_class.__name__} 同步了 {len(terms_to_add)} 个新词汇: {terms_to_add}") # 可选：日志
            else:
                print(f"模型 {model_class.__name__} 没有新的词汇需要同步。")  # 可选：日志

        except Exception as e:
            # 处理异常，例如数据库表可能尚未创建
            print(f"同步模型 {model_class.__name__} 词汇时出错: {e}")

    @classmethod
    def add_restricted_terms(cls, terms):
        """添加限制词，支持单个词或列表/集合。"""
        if isinstance(terms, str):
            cls._restricted_terms.add(terms)
        else:
            cls._restricted_terms.update(set(terms))

    @classmethod
    def remove_restricted_term(cls, term):
        """从限制词集中移除某个词（谨慎使用）。"""
        if term in cls._restricted_terms:
            cls._restricted_terms.remove(term)
            return True
        return False

    @classmethod
    def get_restricted_terms(cls):
        """获取当前所有限制词的副本。"""
        return cls._restricted_terms.copy()

    @classmethod
    def validate_term(cls, value, raise_exception=True):
        """
        验证给定的值是否不在限制词列表中。

        参数:
            value: 待验证的字符串
            raise_exception: 是否在验证失败时抛出异常，默认为True

        返回:
            如果验证通过返回True，否则返回False或抛出异常
        """
        if value in cls._restricted_terms:
            if raise_exception:
                raise ValidationError(
                    f"'{value}' 是受限词汇，请选择其他值。当前限制词库包含: {sorted(cls._restricted_terms)}"
                )
            return False
        return True

    @classmethod
    def is_initialized(cls):
        """返回管理器是否已完成核心词汇初始化。"""
        return cls._is_initialized

    @classmethod
    def sync_terms_from_singleton_model(cls, singleton_instance, field_names):
        """
        从单例模型实例的指定字段同步词汇到限制词集。
        适用于全局配置类模型，这些字段值在系统启动时加载，无需监听保存信号。

        参数:
            singleton_instance: 单例模型的实例对象（通过 getsolo() 等方法获取）
            field_names: 需要同步的字段名列表或元组，如 ['custom_slug', 'custom_article']
        """
        try:
            terms_to_add = set()

            for field_name in field_names:
                # 使用 getattr 安全地获取字段值
                field_value = getattr(singleton_instance, field_name, None)
                # 只添加非空的有效值
                if field_value:
                    terms_to_add.add(field_value)

            if terms_to_add:
                cls.add_restricted_terms(terms_to_add)
                # print(f"从单例模型 {singleton_instance.__class__.__name__} 同步了 {len(terms_to_add)} 个词汇: {terms_to_add}")
            else:
                print(
                    f"词汇获取提示，可忽略：单例模型 {singleton_instance.__class__.__name__} 的指定字段无有效词汇。"
                )

        except Exception as e:
            print(f"同步单例模型词汇时出错: {e}")

    @classmethod
    def validate_term_for_singleton(cls, value, current_instance_value=None, field_name=""):
        """
        专为单例模型设计的验证方法。
        检查给定值是否在限制词库中，并排除与当前实例自身值的冲突。

        参数:
            value: 待验证的值。
            current_instance_value: 单例模型该字段的当前值（即数据库中已存在的值）。
            field_name: 字段名，用于生成清晰的错误信息。
        """
        if not value:  # 如果值为空，则跳过验证
            return

        if value in cls._restricted_terms:
            # 最关键的一步：只有当新值在限制词库中，且这个新值不等于当前实例已有的值时，才报错。
            # 这避免了“自己和自己冲突”的问题。
            if value != current_instance_value:
                raise ValidationError(
                    {field_name: ("'%(value)s' 是受限词汇，请选择其他值。") % {"value": value}}
                )
