# apps/core/views/web.py

import logging
import threading
import urllib

from apps.content.models import Article
from apps.content.models.category import Category
from apps.core.cache.conditional_cache_page import (
    conditional_cache_page,
    dynamic_ratelimit,
)
from apps.core.cache.static_cache import StaticCacheManager
from apps.core.models.global_dns import GlobalDNSConfig
from apps.core.models.sensitive_config import SensitiveConfig
from apps.core.models.site_settings import SiteSettings
from apps.core.models.static_settings import StaticSettings
from apps.core.utils.hash import unhash_id
from apps.core.utils.sensitive_filter import SensitiveFilter
from django.conf import settings
from django.db import models
from django.db.utils import OperationalError, ProgrammingError
from django.http import Http404, HttpResponse

# from links.models import FriendLink
from django.shortcuts import get_object_or_404, redirect
from django.urls import reverse
from django.utils.decorators import method_decorator
from django.views.generic import TemplateView

logger = logging.getLogger(__name__)

# def initialize_configurations():
#     """初始化所有单例配置模型"""
#     """自动初始化core应用下所有单例配置模型"""
#     print('初始化收集项目静态文件')
#     from django.core.management import call_command
#     call_command('collectstatic', '--noinput')
#     try:
#         # 获取core应用的所有模型
#         core_app = apps.get_app_config('core')
#         core_models = core_app.get_models()

#         # 过滤继承自ConfigCommonModel的模型（假设这是单例基类）
#         config_models = [
#             model for model in core_models
#             if issubclass(model, ConfigCommonModel)
#             and model.__name__ != 'ConfigCommonModel'  # 排除基类本身
#         ]
#     except LookupError:
#         # 处理core应用未找到的情况
#         print("Core应用未注册，无法自动发现配置模型")
#         config_models = []

#     # 初始化日志输出
#     print(f"发现{len(config_models)}个配置模型：{[m.__name__ for m in config_models]}")

#     for model in config_models:
#         try:
#             # 强制创建单例实例并加载到缓存
#             obj = model.get_solo()  # 自动创建默认实例
#             obj.save()  # 显式触发保存信号
#             logger.info(f"成功初始化 {model.__name__} 配置")
#             # 确保数据库连接释放
#             close_old_connections()

#         except (OperationalError, ProgrammingError) as e:
#             # 处理数据库未就绪（首次迁移时可能发生）
#             logger.warning(f"数据库未就绪，跳过 {model.__name__} 初始化")
#         except Exception as e:
#             logger.error(f"初始化 {model.__name__} 失败: {str(e)}")
#             # 清除可能的缓存残留
#             cache.delete(model._get_cache_key())


@method_decorator(dynamic_ratelimit(settings.RATE_LIMIT_HOME), name="dispatch")
@method_decorator(conditional_cache_page(settings.INDEX_TIMEOUT), name="dispatch")
class HomeView(TemplateView):

    def get(self, request, *args, **kwargs):
        # 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"HomeView:当前进程常驻内存(RSS)占用: {rss_mb:.2f} MB")
        context = self.get_context_data(**kwargs)
        login_url = reverse("admin:login") + "?next=/admin/core/sitesettings/"
        # try:
        #     try:
        #         with open(settings.BASE_DIR / 'config/config.json', 'r') as f:
        #             GLOBAL_CONFIG = json.load(f)
        #             if len(GLOBAL_CONFIG) < 3:
        #                 initialize_configurations()

        #     except (FileNotFoundError, json.JSONDecodeError):
        #         print('config/config.json缺失，我们进行初始化')
        #         initialize_configurations()
        #     # 尝试获取站点配置
        #     site_settings = SiteSettings.get_solo()
        #     if not site_settings.site_name:
        #         # 执行初始化并强制重定向到Admin
        #         initialize_configurations()
        #         return redirect(login_url)

        # except (OperationalError, ProgrammingError):
        #     # 处理首次迁移后的空数据库情况
        #     initialize_configurations()
        #     return redirect(login_url)
        # except Exception as e:
        #     logger.error(f"初始化检查失败: {str(e)}")
        #     return redirect(login_url)
        # if not site_name:
        #     return redirect('admin:login')  # 重定向到Admin登录页
        site_settings = SiteSettings.get_solo()
        if not site_settings.site_name:
            # 执行初始化并强制重定向到Admin
            return redirect(login_url)
        try:
            filename = request.path_info
            self.static_config = StaticSettings.get_solo()
            manager = StaticCacheManager(
                self.static_config.high_safe, self.static_config.static_index
            )
        except:
            return redirect(login_url)
        # === 新增：子域名匹配栏目逻辑 ===
        # 获取当前请求的完整URL并提取主机名（不含端口和路径）
        full_url = request.build_absolute_uri("/")
        parsed_url = urllib.parse.urlparse(full_url)
        hostname = parsed_url.hostname

        # 检查Category中是否有subdomain值与当前主机名匹配
        try:
            # 使用Q对象进行更灵活的查询，考虑子域名或完整域名匹配
            matching_category = Category.objects.filter(subdomain=hostname).first()

            if matching_category:
                self.object = matching_category  # 将匹配到的栏目设置为self.object
                # 调用栏目上下文处理方法
                context = self.get_context_data(**kwargs)
                # 获取模板（使用栏目的模板逻辑）
                self.template_name = self.get_template_names()
                # 渲染响应
                response = self.render_to_response(context)
                # 静态化缓存处理（如果你需要）
                if hasattr(self, "static_config") and self.static_config.static_key:
                    manager = StaticCacheManager(
                        self.static_config.high_safe, self.static_config.static_index
                    )
                    filename = request.path_info
                    manager.create(filename, response.render().content.decode("utf-8"))
                return response
        except (OperationalError, ProgrammingError) as e:
            logger.warning(f"查询Category表失败（可能表未就绪）: {str(e)}")
            # 忽略错误，继续执行后续逻辑
        except Exception as e:
            logger.error(f"子域名匹配栏目过程发生未知错误: {str(e)}")
            # 同样忽略，避免影响主流程
        # 新增DNS配置检查
        dns_config = GlobalDNSConfig.get_solo()
        if (
            dns_config.status == "enabled"
            and dns_config.primary_domain
            and dns_config.dns_type == "content_to_home"
        ):
            # 处理域名替换逻辑
            domain = request.get_host()
            article_id_hash = domain.replace(f".{dns_config.primary_domain}", "")
            if article_id_hash and article_id_hash != "www" and domain != dns_config.primary_domain:

                try:
                    article_id = int(unhash_id(article_id_hash))

                    self.object = get_object_or_404(
                        Article.objects.prefetch_related("category"), pk=article_id, status=99
                    )
                    filename = f"/article/{self.object.pk}.html"
                except (ValueError, Article.DoesNotExist):
                    raise Http404
        # 获取静态内容

        if self.static_config.static_key:

            static_content = manager.get(filename)

            if static_content:
                return HttpResponse(static_content)

            # 执行父类get方法完成常规处理
        response = super().get(request, *args, **kwargs)
        if self.static_config.static_key:
            manager.create(filename, response.render().content.decode("utf-8"))

        return response

    def get_template_names(self):
        theme = settings.THEME_NAME
        templates = []
        # 如果 self.object 是 Category（子域名匹配的情况）
        if hasattr(self, "object") and isinstance(self.object, Category):
            if self.object.index_template:
                templates.append(
                    self.object.index_template.replace(f"{settings.BASE_DIR}/templates/themes/", "")
                )
            model_name = self.object.content_type.model
            templates.extend(
                [
                    f"themes/{theme}/templates/category/{model_name}_list.html",
                    f"themes/default/templates/category/{model_name}_list.html",
                    f"themes/{theme}/templates/category/category_list.html",  # 更通用的回退
                    "themes/default/templates/category/category_list.html",
                ]
            )
            return templates

        # 优先使用文章/栏目指定模板
        if hasattr(self, "object") and isinstance(self.object, Article):
            if self.object.template:
                templates.append(
                    self.object.template.replace(f"{settings.BASE_DIR}/templates/themes/", "")
                )
            if hasattr(self.object, "category") and self.object.category.content_template:
                templates.append(
                    self.object.category.content_template.replace(
                        f"{settings.BASE_DIR}/templates/themes/", ""
                    )
                )

        # 默认模板路径
        if hasattr(self, "object") and self.object:
            model_name = self.object.category.content_type.model
            templates.extend(
                [
                    f"themes/{theme}/templates/item/{model_name}_item.html",
                    "themes/default/templates/item/{model_name}_item.html",
                ]
            )
        else:
            # 如果没有object，使用默认首页模板
            templates = [
                f"themes/{theme}/templates/index.html",
                "themes/default/templates/index.html",
            ]

        return templates

    def get_context_data(self, **kwargs):
        theme = settings.THEME_NAME  # 正确访问方式
        context = super().get_context_data(**kwargs)
        if hasattr(self, "object") and self.object:
            if isinstance(self.object, Article):
                # 如果是文章对象，调用文章详情页的上下文处理
                context.update(self.get_article_context(context))
            elif isinstance(self.object, Category):
                # 如果是栏目对象，调用栏目页的上下文处理
                context.update(self.get_category_context(context))
        # context['featured_articles'] = Article.objects.filter(status=99)[:5]
        # context['friend_links'] = FriendLink.objects.filter(is_active=True)

        return context

    def get_article_context(self, context):
        obj = self.object
        from apps.core.models import TagPageConfig

        tag_config = TagPageConfig.get_solo()
        if not obj.cut_keywords.exists() and tag_config.word_split_enabled:

            if tag_config.concurrent_update_enabled:

                def update_task():
                    # 在线程内重新获取对象
                    try:
                        obj.update_cut_keywords()
                    except Exception as e:
                        print(f"Error updating cut keywords: {e}")

                thread = threading.Thread(target=update_task)
                thread.daemon = True
                thread.start()
            else:
                obj.update_cut_keywords()
        obj_update_fields = []
        if not obj.previous_obj:
            previous_article = (
                Article.objects.filter(status=99, create_time__lt=obj.create_time)
                .order_by("-create_time")
                .first()
            )
            if previous_article:
                obj.previous_obj = previous_article
                obj_update_fields.append("previous_obj")
                # 同步更新相关文章
                previous_article.next_obj = obj
                previous_article.save(update_fields=["next_obj"])
        if not obj.next_obj:
            next_article = (
                Article.objects.filter(status=99, create_time__gt=obj.create_time)
                .order_by("create_time")
                .first()
            )
            if next_article:
                obj.next_obj = next_article
                obj_update_fields.append("next_obj")
                # 同步更新相关文章
                next_article.previous_obj = obj
                next_article.save(update_fields=["previous_obj"])

            # 更新当前文章关联字段‌:ml-citation{ref="2" data="citationList"}
        if obj_update_fields:
            obj.save(update_fields=obj_update_fields)
        # 开始处理敏感词
        config = SensitiveConfig.get_solo()
        sensitive_filter = SensitiveFilter(config)
        sensitive_fields = ["title", "meta_description", "content"]
        if config.filter_switch:
            for field in sensitive_fields:
                # 1. 检查字段是否存在
                if not hasattr(obj, field):
                    continue

                # 2. 获取原始值并处理
                original_value = getattr(obj, field)
                processed_value = sensitive_filter.process_text(original_value)

                setattr(obj, field, processed_value)

        context["obj"] = obj
        # 相关标签
        context["tags"] = obj.related_tags.all()
        # 相关文章逻辑
        # 通过标签获取相关文章
        related_by_tags = (
            Article.objects.filter(related_tags__in=obj.related_tags.all(), status=99)
            .select_related("category")
            .exclude(pk=obj.pk, status=99)
            .annotate(tag_count=models.Count("related_tags"))
            .order_by("-tag_count", "-create_time")
            .distinct()
            .only(
                "title",
                "meta_description",
                "pk",
                "update_time",
                "thumb_image",
                "category__id",
                "category__name",
                "category__slug",
            )[:10]
        )
        context["related_articles"] = related_by_tags
        return context

    def get_category_context(self, context):
        """
        处理栏目页的上下文，模拟CategoryDetailView的部分逻辑
        注意：self.object 此时应为匹配到的 Category 对象
        """
        category = self.object  # 获取当前匹配的栏目对象

        # 确保上下文中有基本的栏目对象引用
        context["object"] = category  # DetailView 通常使用 object
        context["category"] = category  # 也添加一个别名，便于模板使用
        context["obj"] = category  # 与你原有代码中的命名习惯保持一致

        context["active"] = self.object.slug

        # 3. 权限检查（可选，根据你的需求决定是否在HomeView中加入）
        # 虽然你在CategoryDetailView中有 staff_only 和 allowed_groups 检查，
        # 但在 HomeView 中通过子域名匹配后，如果也需要这些限制，可以在此添加。
        # 如果检查不通过，可以抛出 PermissionDenied 异常或返回一个错误的 HttpResponse。
        # 例如：
        if category.staff_only and not self.request.user.is_staff:
            from django.core.exceptions import PermissionDenied

            raise PermissionDenied("该内容仅限工作人员查看")
        if (
            category.allowed_groups.exists()
            and not category.allowed_groups.filter(id__in=self.request.user.groups.all()).exists()
        ):
            from django.core.exceptions import PermissionDenied

            raise PermissionDenied("您所在的用户组无权查看此内容")

        # 4. 你可以在 context 中添加任何其他栏目页模板需要的数据

        return context


# def server_error(request):
#     theme = settings.THEME_NAME
#     template_name = f"themes/{theme}/error.html"  # 自动适配当前主题
#     return HttpResponseServerError(render(request, template_name, '500.html'))
