import threading

from django.core.cache import cache
from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.db import models


class ConfigCommonModel(models.Model):
    _lock = threading.Lock()  # 类级线程锁
    _instance = None

    class Meta:
        abstract = True

    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super().__new__(cls)
        return cls._instance

    def __repr__(self):
        """
        为所有配置模型提供统一的、开发者友好的字符串表示。
        优先尝试获取具有标识性的字段（如 name, title, site_name），
        其次是模型的 verbose_name。
        """
        # 尝试获取可能存在的标识性字段
        identifier = None
        for attr in ["site_name", "name", "title", "verbose_name"]:
            identifier = getattr(self, attr, None)
            if identifier:
                break

        # 如果找不到标识字段，则使用模型的详细名称
        if not identifier:
            identifier = getattr(self, "_meta").verbose_name

        # 返回标准格式的字符串
        return f"<{self.__class__.__name__}: {identifier} (ID: {getattr(self, 'id', 'No-ID')})>"

    def save(self, *args, **kwargs):
        # 检查是否已存在实例
        # if self.__class__.objects.exists() and not self.pk:
        #     # 如果已经存在实例且当前实例没有主键（即新建实例）
        #     raise ValidationError(f"只能创建一个{self._meta.verbose_name}实例")
        # print("=== 模型实例的当前字段值（保存前）===")
        # for field in self._meta.fields:
        #     field_name = field.name
        #     field_value = getattr(self, field_name)
        #     print(f"模型字段 {field_name}: {field_value}")
        self.pk = 1
        super().save(*args, **kwargs)
        # 更新缓存
        cache.set(self._get_cache_key(), self, timeout=None)
        print(f"Updated cache for {self._meta.model_name}")
        cache.delete("templates_global_cache")  # 用来更新模板上下文变量

    def delete(self, *args, **kwargs):
        # 禁止删除实例
        raise ValidationError(f"不能删除{self._meta.verbose_name}实例")

    @classmethod
    def _get_cache_key(cls):
        """生成模型专属缓存键"""
        return f"config_{cls._meta.model_name}"

    @classmethod
    def is_database_ready(cls):
        """检查数据库是否就绪"""
        from django.db import connection

        try:
            with connection.cursor() as cursor:
                cursor.execute("SELECT 1")
            return True
        except Exception:
            return False

    @classmethod
    def get_solo(cls):
        """
        线程安全的单例获取方法 - 修复版
        """
        # 确保数据库就绪检查更加健壮
        if not cls.is_database_ready():
            print("数据库未就绪，返回默认配置")
            return cls(id=1)  # 返回默认实例

        try:
            cache_key = cls._get_cache_key()
            # 验证缓存键有效性
            if not cache_key or not isinstance(cache_key, str):
                cache_key = f"{cls.__name__}_solo_config"

            # 第一层缓存检查
            instance = cache.get(cache_key)
            if instance is not None:  # 明确检查不是None
                return instance

            with cls._lock:
                # 第二层缓存检查（加锁后）
                instance = cache.get(cache_key)
                if instance is not None:  # 明确检查不是None
                    return instance

                # 核心修复：确保无论如何都返回有效实例
                try:
                    instance, created = cls.objects.get_or_create(id=1)

                    # 新创建实例的默认值设置
                    if created:
                        instance = cls._setup_defaults(instance, cls.__name__)
                        instance.save()

                except cls.MultipleObjectsReturned:
                    print(f"{cls._meta.verbose_name}检测到多个配置实例，正在清理...")
                    cls._cleanup_duplicates()
                    instance = cls.objects.get(id=1)

                except Exception as db_error:
                    print(f"数据库操作失败: {db_error}，返回默认实例")
                    instance = cls(id=1)

                # 确保实例不为None再缓存
                if instance is not None:
                    cache.set(cache_key, instance, timeout=None)
                else:
                    # 最终保障：创建全新实例
                    instance = cls(id=1)
                    cache.set(cache_key, instance, timeout=None)

                return instance
        except Exception as e:
            # 特别捕获并处理数据库操作异常
            error_msg = str(e)

            # 判断是否为常见的数据库连接或访问错误
            if "1045" in error_msg:
                print(
                    f"【严重错误】数据库连接被拒绝 - 请检查 /config/connection_strings.ini 配置的用户名和密码是否正确。原始错误: {error_msg}"
                )
            elif "2003" in error_msg or "10061" in error_msg:
                print(
                    f"【连接错误】无法连接到数据库服务器 - 请检查数据库服务是否启动，以及 /config/connection_strings.ini 中 HOST 和 PORT 配置。原始错误: {error_msg}"
                )
            elif "1049" in error_msg:
                print(
                    f"【数据库错误】指定的数据库不存在 - 请先在数据库管理系统中创建相应的数据库，以及检查 /config/connection_strings.ini 中的数据库配置文件是否填写正确。原始错误: {error_msg}"
                )
            elif "1146" in error_msg or "doesn't exist" in error_msg:
                print(
                    f"【数据库表错误】{cls._meta.verbose_name} 获取配置需要的数据库表不存在: {error_msg}"
                )
                print("请执行以下命令创建数据库表:")
                print("python manage.py makemigrations")
                print("python manage.py migrate")
            elif "1054" in error_msg or "Unknown column" in error_msg:
                print(
                    f"【数据库字段错误】{cls._meta.verbose_name} 需要的数据库字段不存在: {error_msg}"
                )
                print("这可能是因为模型字段已变更但数据库未同步")
            elif "'NoneType' object has no attribute 'save'" in error_msg:
                print(f"【对象错误】尝试保存空对象: {error_msg}")
                print("请检查数据库查询是否返回了有效结果")
            else:
                # 其他未知异常
                print(f"{cls._meta.verbose_name} 获取配置时发生未知错误: {error_msg}")
            return cls(id=1)

    @staticmethod
    def _setup_defaults(instance, class_name):
        """设置各类配置的默认值"""
        defaults_config = {
            "AdminSettings": {
                "stat_models": ["content.article", "content.tag", "content.category"],
                "core_update_models": ["content.article"],
            },
            "UrlPush": {"content_models": ["content.article"]},
            "SitemapConfig": {
                "content_models": ["content.article", "content.tag", "content.category"]
            },
            "SearchConfig": {
                "content_models": ["content.article", "content.tag", "content.category"],
                "content_fields": ["title"],
            },
            "GlobalDNSConfig": {"primary_domain": "localhost"},  # 添加默认域名
        }

        if class_name in defaults_config:
            for field, value in defaults_config[class_name].items():
                if not getattr(instance, field, None):
                    setattr(instance, field, value)

        return instance

    @classmethod
    def _cleanup_duplicates(cls):
        """清理重复实例的防御性方法"""
        from django.db import transaction

        with transaction.atomic():
            # 锁定表防止并发操作
            instances = list(cls.objects.select_for_update().order_by("pk"))
            if len(instances) > 1:
                # 保留pk=1的实例，删除其他
                cls.objects.exclude(pk=1).delete()
