# apps/core/signals.py
import re

from apps.core.models.admin_settings import AdminSettings
from apps.core.models.ai_config import AiConfig
from apps.core.models.auxiliary import AuxiliaryConfig
from apps.core.models.cacheconfig import CacheConfig
from apps.core.models.debug_settings import DebugSetting
from apps.core.models.email_setting import EmailSetting
from apps.core.models.ratelimit import RateLimitConfig
from apps.core.models.site_settings import SiteSettings
from apps.core.models.theme_settings import Theme
from apps.core.models.url_style import UrlStyle
from apps.core.utils.config_manager import update_config
from django.apps import apps
from django.contrib.auth import get_user_model
from django.db import OperationalError, ProgrammingError
from django.db.models.signals import post_migrate, post_save, pre_save
from django.dispatch import receiver
from slugify import slugify


@receiver(post_save, sender=AuxiliaryConfig)
@receiver(post_save, sender=DebugSetting)
@receiver(post_save, sender=AdminSettings)
@receiver(post_save, sender=EmailSetting)
@receiver(post_save, sender=UrlStyle)
@receiver(post_save, sender=AiConfig)
@receiver(post_save, sender=RateLimitConfig)
@receiver(post_save, sender=CacheConfig)
@receiver(post_save, sender=Theme)
@receiver(post_save, sender=SiteSettings)
def sync_to_config(sender, instance, **kwargs):
    model_name = sender.__name__
    data = {f.name: getattr(instance, f.name) for f in sender._meta.fields if f.name != "id"}
    update_config(model_name, data)


# 使用receiver装饰器将函数连接到post_migrate信号，并指定sender为CoreConfig
# apps/core/signals.py


@receiver(post_migrate, dispatch_uid="initialize_singleton_models")
def initialize_singleton_models(sender, **kwargs):
    """
    信号接收函数，用于在数据库迁移后自动初始化所有单例配置模型。
    自动发现core应用下所有继承自ConfigCommonModel的非抽象模型，且managed不为False的模型。
    """
    # 提前处理：确保系统有一个admin超级用户
    User = get_user_model()
    try:
        # 检查是否已存在用户
        if not User.objects.exists():
            print("系统中无用户，开始创建默认超级用户...")
            raw_password = "admin888"

            # 创建超级用户 (密码会自动哈希处理)
            first_user = User.objects.create_superuser(
                username="admin",
                email="admin@example.com",
                password=raw_password,  # Django会自动对明文密码进行哈希
            )
            print("默认超级用户创建成功！")
            print("=" * 50)
            print("重要：请妥善保存以下登录信息")
            print(f"用户名: admin")
            print(f"邮箱: admin@example.com")
            print(f"密码: {raw_password}")  # 打印明文密码供首次使用
            print("=" * 50)
            print("提示：请在生产环境中及时更改此密码！")

    except Exception as e:
        print(f"创建用户时发生错误: {e}")
        # 可选：尝试创建不关联用户的AiConfig实例（如果模型允许editor为空）
        # instance = model.objects.create(editor=None)
    # 确保只在core应用迁移后执行
    if sender.name != "apps.core":  # 请根据你的实际应用名称修改
        return

    print("开始自动初始化核心配置模型...")
    # 初始化统计变量
    initialized_count = 0
    already_exist_count = 0
    error_count = 0
    database_not_ready = False
    error_messages = []

    try:
        # 1. 获取core应用的所有模型
        core_app = apps.get_app_config("core")
        core_models = core_app.get_models()

        # 2. 动态过滤出所有继承自ConfigCommonModel的非抽象且受管理的模型
        from .models import ConfigCommonModel  # 从当前应用导入基类

        config_models = [
            model
            for model in core_models
            if (
                issubclass(model, ConfigCommonModel)
                and not model._meta.abstract
                and getattr(model._meta, "managed", True) is not False
            )  # 关键检查：排除 managed=False 的模型
        ]

        print(f"发现 {len(config_models)} 个需要初始化的配置模型")

        # 3. 遍历并初始化每一个模型
        for model in config_models:
            try:
                # 使用exists()判断是否存在实例，不存在则创建
                if not model.objects.exists():
                    # 创建实例。如果字段有默认值，会自动填充。
                    instance = model.objects.create()
                    initialized_count += 1
                else:
                    already_exist_count += 1

            except (OperationalError, ProgrammingError) as e:
                print(f"initialize_singleton_models  OperationalError, ProgrammingError:{e}")
                # 处理数据库表可能还不存在的极端情况（例如首次迁移）
                database_not_ready = True
                error_count += 1
                # 不再为每个模型单独打印数据库错误

            except Exception as e:
                print(f"initialize_singleton_models Exception:{e}")
                # 捕获其他所有意外错误
                error_count += 1
                error_messages.append(f"{model.__name__}: {str(e)}")

    except LookupError:
        print(
            "错误: 无法找到 'core' 应用配置。请检查应用是否已在 settings.INSTALLED_APPS 中正确注册。"
        )
    except ImportError:
        print("错误: 无法从 apps.core.models 导入 ConfigCommonModel。请检查基类名称和路径。")
    except Exception as e:
        print(f"错误: 初始化过程中发生全局错误: {e}")
        return
    # 4. 统一输出初始化结果摘要
    print("\n" + "=" * 50)
    print("核心配置模型初始化完成摘要")
    print("=" * 50)

    if initialized_count > 0:
        print(f"✅ 成功初始化: {initialized_count} 个模型")

    # if already_exist_count > 0:
    #     print(f"ℹ️  已存在跳过: {already_exist_count} 个模型")

    if database_not_ready:
        print(f"⏳ 数据库未就绪: 部分模型因数据库表未创建而初始化失败")
        print("   请确保已执行所有迁移，系统将在下次适合机会再次进行初始化。")

    if error_count > 0 and not database_not_ready:
        print(f"❌ 初始化错误: {error_count} 个模型")
        for msg in error_messages:
            print(f"   - {msg}")

    if error_count == 0 and not database_not_ready and initialized_count > 0:
        print("✅ 所有模型初始化完成！")

    print("=" * 50)

    # 收集静态文件
    from io import StringIO

    from django.core.management import call_command

    try:
        output = StringIO()
        call_command(
            "collectstatic",
            interactive=False,
            clear=True,  # 根据需求选择是否清除
            stdout=output,
            verbosity=1,
        )

        output_str = output.getvalue()
        output.close()

        # 简单提取文件数量
        match = re.search(r"(\d+)\s+static files? copied", output_str)
        if match:
            print(f"✅ 收集静态文件完成，复制了 {match.group(1)} 个文件")
        else:
            print("✅ 收集静态文件完成")

    except Exception as e:
        print(f"❌ 收集静态文件失败: {str(e)}")
