from apps.core.utils.get_models import autoload_user_apps
from django.apps import apps
from django.core.exceptions import ValidationError
from django.db import models
from django.utils.translation import gettext_lazy as _  # 添加gettext_lazy导入

from .common import ConfigCommonModel


class AdminSettings(ConfigCommonModel):
    ADMIN_PATH_HELP = _("""
    修改DjacoreCMS admin的默认路径（以/结尾），例如：'myadmin/'。留空使用默认路径'admin/'
    """)

    admin_base_path = models.CharField(
        verbose_name=_("Admin路径"),
        max_length=50,
        blank=True,
        default='admin/',
        help_text=ADMIN_PATH_HELP
    )
    admin_site_name = models.CharField(
        verbose_name=_('后台名称'),
        max_length=100,
        blank=True,
        help_text=_('设置个性化后面名称。')
    )

    stat_models = models.JSONField(
        verbose_name=_("核心统计模型"),
        default=list,
        help_text=_("选择要在Admin首页显示的统计模型")
    )

    user_app_models = models.JSONField(
        verbose_name=_("用户自建应用模型"),
        default=list,
        help_text=_("选择要管理的用户空间模型")
    )
    
    update_tracking_days = models.PositiveIntegerField(
        verbose_name=_("更新追踪天数"), 
        default=7, 
        help_text=_("显示最近多少天的内容更新统计")
    )

    core_update_models = models.JSONField(
        verbose_name=_("核心模型"),
        default=list,
        help_text=_("选择要追踪的核心内容模型（来自content应用）")
    )

    user_update_models = models.JSONField(
        verbose_name=_("用户自建模型更新"),
        default=list,
        help_text=_("选择要追踪的用户空间内容模型")
    )

    class Meta:
        verbose_name = _("后台配置")
        verbose_name_plural = _("后台配置")

    def __str__(self):
        return str(_("后台配置"))  # 使用str()包装确保返回字符串

    def clean(self):
        """验证数据格式"""
        # 验证路径格式
        if self.admin_base_path:
            if not self.admin_base_path.endswith('/'):
                raise ValidationError({'admin_base_path': _('路径必须以/结尾')})
            if any(c in self.admin_base_path for c in ' #?*'):
                raise ValidationError({'admin_base_path': _('包含非法字符')})

        # 验证模型选择格式
        for field in ['stat_models', 'user_app_models']:
            value = getattr(self, field)
            if not isinstance(value, list):
                raise ValidationError({field: _('必须为数组格式')})
            if any(not isinstance(item, str) for item in value):
                raise ValidationError({field: _('包含非字符串元素')})
                
        # 验证更新天数
        if self.update_tracking_days < 1:
            raise ValidationError({'update_tracking_days': _('天数必须大于等于1')})

        # 验证新模型字段
        for field in ['core_update_models', 'user_update_models']:
            value = getattr(self, field)
            if not isinstance(value, list):
                raise ValidationError({field: _('必须为数组格式')})
            if any(not isinstance(item, str) for item in value):
                raise ValidationError({field: _('包含非字符串元素')})

    def save(self, *args, **kwargs):
        # 检查是否是新建对象且content_models字段为空列表
        if self.pk is None:
            if self.stat_models == []:
                self.stat_models = [
                    "content.article", "content.tag", "content.category"
                ]
            if self.core_update_models == []:
                self.core_update_models = [
                    "content.article",
                ]
        super().save(*args, **kwargs)

    @staticmethod
    def get_content_models_choices():
        """获取content应用的可用模型选项"""
        from django.apps import apps
        try:
            app_config = apps.get_app_config('content')
            return [(f"{model._meta.app_label}.{model._meta.model_name}",
                     model._meta.verbose_name)
                    for model in app_config.get_models()
                    if model._meta.model_name not in [
                        'contentmanager',
                    ]]
        except LookupError:
            return []

    @staticmethod
    def get_user_space_choices():
        """获取用户空间应用的可用模型选项"""
        from django.apps import apps
        models = []
        for app_name in autoload_user_apps():
            try:
                app_config = apps.get_app_config(app_name.split('.')[-1])
                models.extend([
                    (f"{model._meta.app_label}.{model._meta.model_name}",
                     f"{app_config.verbose_name} - {model._meta.verbose_name}")
                    for model in app_config.get_models()
                ])
            except (LookupError, ImportError):
                continue
        return models

    def get_stat_models(self):
        """
        获取合并后的模型列表
        返回: 包含所有选中模型类的列表
        """
        combined = []

        # 合并两个字段的模型标识
        all_models = self.stat_models + self.user_app_models

        # 去重处理
        seen = set()
        unique_models = [
            x for x in all_models if not (x in seen or seen.add(x))
        ]

        # 转换为模型类
        for model_str in unique_models:
            try:
                app_label, model_name = model_str.split('.')
                model_class = apps.get_model(app_label, model_name)
                combined.append(model_class)
            except (ValueError, LookupError, AttributeError) as e:
                # 处理无效模型标识
                print(f"无效的模型标识 {model_str}: {str(e)}")
                continue

        return combined

    def get_update_models(self):
        """
        获取需要追踪更新的模型类列表
        返回: (模型类列表, 追踪天数)
        """
        combined = []
        all_models = self.core_update_models + self.user_update_models

        seen = set()
        for model_str in all_models:
            if model_str in seen:
                continue
            seen.add(model_str)

            try:
                app_label, model_name = model_str.split('.')
                model_class = apps.get_model(app_label, model_name)
                combined.append(model_class)
            except (ValueError, LookupError):
                continue

        return combined, self.update_tracking_days

    # 扩展动态选项方法
    @staticmethod
    def get_core_update_choices():
        """复用统计模型的选项"""
        return AdminSettings.get_content_models_choices()

    @staticmethod
    def get_user_update_choices():
        """复用用户空间模型的选项"""
        return AdminSettings.get_user_space_choices()