import os
import threading

# import jieba
from apps.core.services.django_sys import uWSGI_Reload
from apps.core.utils.config_manager import (
    check_and_patch_uwsgi_ini,
    initialize_configurations,
    is_config_valid,
)
from apps.core.utils.restricted_term_manager import RestrictedTermManager
from django.apps import AppConfig
from django.conf import settings
from django.db.backends.signals import connection_created


class CoreConfig(AppConfig):
    default_auto_field = "django.db.models.BigAutoField"
    name = "apps.core"
    verbose_name = "系统设置"
    default = True

    # 类变量，用于标记初始化是否已完成，防止重复初始化
    _initialized = False

    def ready(self):
        # 确保信号处理器被加载（如果signals.py中有其他信号处理）
        import apps.core.signals

        # 注册数据库连接建立后的信号处理器
        # 使用dispatch_uid防止在开发服务器重载时重复连接信号
        connection_created.connect(
            self._on_database_connected, dispatch_uid="core_config_db_connect"
        )

        # 预加载jieba（此项不依赖数据库，可安全放在ready中）
        # print("Preloading jieba...")
        # list(jieba.cut("预热", cut_all=False))
        # print("✅ Jieba preloading finished.")
        # import os

        # import psutil

        # # 获取当前进程的ID和对象
        # process = psutil.Process(os.getpid())

        # # 在代码关键点获取内存信息（单位通常为字节，可转换为MB）
        # memory_info = process.memory_info()
        # rss_mb = memory_info.rss / 1024 / 1024
        # print(f"当前进程常驻内存(RSS)占用: {rss_mb:.2f} MB")

    def _on_database_connected(self, sender, connection, **kwargs):
        if connection.alias != "default":
            return

        # 类级别的权限检查标记
        if not hasattr(self.__class__, "_permissions_checked"):
            if not settings.DEBUG:
                self._check_and_ensure_permissions()
            self.__class__._permissions_checked = True

        # 原有的初始化逻辑
        if not self._initialized:
            print(f"Database connection established. Running initialization...")
            self._initialized = True
            self._run_initialization()
            self.initialize_restricted_terms()

    def _run_initialization(self):
        """运行初始化逻辑，包含重试机制"""
        import time

        from django.db import OperationalError

        max_retries = 3
        for attempt in range(max_retries):
            try:
                # 检查配置文件有效性并执行必要的初始化
                if not is_config_valid():
                    print("⚠️ 配置文件缺失或无效，执行初始化...")
                    initialize_configurations()
                else:
                    print("✅ 配置文件检查通过")
                check_and_patch_uwsgi_ini()

                # 2. 初始化或轮换 SECRET_KEY
                self._initialize_secret_key()
                print("✅ Core configuration initialization completed successfully.")
                break
            except OperationalError as e:
                # 处理数据库连接错误
                if "MySQL server has gone away" in str(e) or "Lost connection" in str(e):
                    if attempt < max_retries - 1:
                        wait_time = (attempt + 1) * 2
                        print(
                            f"⚠️ 数据库连接失败 (尝试 {attempt + 1}/{max_retries}), {wait_time}秒后重试..."
                        )
                        self._close_all_connections()
                        time.sleep(wait_time)
                        continue
                    else:
                        print("❌ 数据库连接重试多次后失败，请检查MySQL服务是否正常运行。")
                else:
                    # 其他类型的OperationalError
                    print(f"❌ 数据库操作错误: {e}")
            except Exception as e:
                # 捕获其他可能的异常
                print(f"❌ 初始化过程中发生未预期的错误: {e}")
                break

    def _close_all_connections(self):
        """安全地关闭所有数据库连接，用于重试前清理环境"""
        from django.db import connections

        try:
            for conn in connections.all():
                if conn.connection:
                    conn.close()
        except Exception as e:
            print(f"⚠️ 关闭数据库连接时出现错误 (可能可忽略): {e}")

    def initialize_restricted_terms(self):
        """
        统一的初始化方法，封装所有限制词管理器的设置逻辑。
        """
        # 1. 初始化核心系统词汇和自定义词汇
        system_terms = ["admin", "category", "tags", "wiki", "article", "user", "profile"]
        custom_terms = ["dashboard", "settings", "config"]

        RestrictedTermManager.initialize_core_terms(
            system_terms=system_terms, custom_terms=custom_terms
        )
        try:
            from django.apps import apps

            # 获取项目中所有已注册的模型类
            all_models = apps.get_models()

            # 提取每个模型类的名称（小写）
            model_names = set()
            for model in all_models:
                # 获取模型的名称（通常是类名的小写形式）
                model_name = model.__name__.lower()
                model_names.add(model_name)

                # 也可以添加模型的verbose_name（如果有定义且是字符串）
                # try:
                #     verbose_name = model._meta.verbose_name
                #     if verbose_name and isinstance(verbose_name, str):
                #         model_names.add(verbose_name.lower())
                # except:
                #     pass

            # 将模型名添加到限制词库
            if model_names:
                RestrictedTermManager.add_restricted_terms(model_names)
                # print(f"已自动添加 {len(model_names)} 个模型名到限制词库: {sorted(model_names)}")

        except Exception as e:
            print(f"自动添加模型名时出现警告: {e}")

        # 2. 同步现有动态模型的词汇（例如Category的slug）
        try:
            from apps.content.models import Category

            RestrictedTermManager.sync_terms_from_model(Category, "slug")
        except Exception as e:
            print(f"同步Category模型词汇时出现警告: {e}")

        # 3. 【新增】同步单例模型的配置词汇
        try:
            from apps.core.models import UrlStyle

            # 获取单例模型的实例
            url_style_instance = UrlStyle.objects.get()  # 或使用 getsolo() 方法
            # 指定需要同步的字段，只要字段有值就纳入限制词库
            fields_to_sync = ["custom_slug", "custom_article", "tag_identifier"]
            RestrictedTermManager.sync_terms_from_singleton_model(
                url_style_instance, fields_to_sync
            )

        except Exception as e:
            # 处理异常，例如UrlStyle表为空或尚未创建
            print(f"同步单例模型UrlStyle词汇时出现警告: {e}。这可能在首次部署时发生。")

        print("限制词管理器初始化完成。")

    def _initialize_secret_key(self):
        """使用 SecretKeyManager 初始化密钥"""
        try:
            from apps.core.utils.secret_manager import secret_manager

            result = secret_manager.initialize_or_rotate_secret_key()

            if result["action"] == "initialized":
                print("🔐 系统密钥已初始化")
                print(f"   密钥长度: {len(result['new_key'])} 字符")

                if result["need_restart"]:
                    # 创建一个线程来执行 uWSGI_Reload 函数
                    reload_thread = threading.Thread(target=uWSGI_Reload)
                    reload_thread.daemon = (
                        True  # 设置为守护线程，主线程退出时它会跟随退出（可选，根据你的需求）
                    )
                    reload_thread.start()  # 启动线程
                    print("⚠️  请重启应用以使用新密钥")

            elif result["action"] == "rotated":
                print("🔄 密钥已自动轮换")
                print(f"   原密钥已使用: {result['key_age_days']} 天")

                if result["need_restart"]:
                    # 创建一个线程来执行 uWSGI_Reload 函数
                    reload_thread = threading.Thread(target=uWSGI_Reload)
                    reload_thread.daemon = (
                        True  # 设置为守护线程，主线程退出时它会跟随退出（可选，根据你的需求）
                    )
                    reload_thread.start()  # 启动线程
                    print("⚠️  请重启应用以使用新密钥")

            elif result["action"] == "warning":
                print(f"⚠️  密钥警告: {result['message']}")

            elif result["action"] == "mismatch":
                print(f"⚠️  密钥不一致: {result['message']}")

            elif result["action"] == "none":
                print("✅ 密钥状态正常")

        except ImportError:
            print("⚠️  无法导入 SecretKeyManager，跳过密钥初始化")

    def _check_and_ensure_permissions(self):
        """
        检查并确保所需目录的写入权限
        """
        REQUIRED_WRITABLE_DIRS = [
            os.path.join(settings.BASE_DIR, "media"),
            os.path.join(settings.BASE_DIR, "config"),
            os.path.join(settings.BASE_DIR, "logs"),
            os.path.join(settings.BASE_DIR, "html"),
        ]

        try:
            # 动态导入，避免循环导入
            from .utils.ensure_dir_permissions import ensure_dir_permissions

            ensure_dir_permissions(REQUIRED_WRITABLE_DIRS)
            print("✅ 目录权限验证通过")

        except ImportError as e:
            print(f"⚠️ 无法导入权限验证工具: {e}")
            print("提示：请检查 apps.core.utils 模块是否正确实现 ensure_dir_permissions 函数")

        except PermissionError as e:
            print(f"❌ 目录权限不足: {e}")
            print("致命错误：应用需要写入权限才能正常运行")
            # 可以选择抛出异常阻止应用启动
            # raise

        except FileNotFoundError as e:
            print(f"⚠️ 目录不存在: {e}")
            print("提示：尝试创建缺失目录...")
            try:
                for dir_path in REQUIRED_WRITABLE_DIRS:
                    if not os.path.exists(dir_path):
                        os.makedirs(dir_path, exist_ok=True)
                        print(f"已创建目录: {dir_path}")
            except Exception as create_error:
                print(f"❌ 创建目录失败: {create_error}")

        except OSError as e:
            print(f"⚠️ 操作系统错误: {e}")
            print("提示：可能是磁盘空间不足或文件系统权限问题")

        except Exception as e:
            print(f"⚠️ 权限验证过程中出现未预期的错误: {e}")
            import traceback

            traceback.print_exc()  # 打印完整堆栈跟踪`


# 下面这个表格详细解释了您给出的规则示例，并补充了Django的默认行为。
# 规则模式
# 含义与作用
# 匹配示例
# '*.txt'
# 忽略所有扩展名为 .txt的文件，无论它们位于哪个目录下。
# notes.txt, static/docs/readme.txt
# 'tests'
# 忽略所有名为 tests的文件夹本身及其内部所有内容。
# app/static/tests/, app/static/tests/test.js
# 'node_modules'
# 忽略所有名为 node_modules的文件夹本身及其内部所有内容。常用于排除前端依赖库。
# static/node_modules/, static/node_modules/jquery/
# 'src/*.map'
# 忽略在 src目录下（不递归其子目录）的 .map文件。
# static/src/main.js.map
# 'CVS', '.*', '*~'
# Django 默认忽略的模式：版本控制目录、所有以点开头的文件（如.DS_Store）、以及以波浪号结尾的备份文件。
# CVS/, .gitignore, file.txt~
from django.contrib.staticfiles.apps import StaticFilesConfig


class MyStaticFilesConfig(StaticFilesConfig):
    # 你的自定义忽略列表
    ignore_patterns = ["aiwords", "tag_words", "txt_files"]
