import os
import threading

from apps.core.cache.static_cache import StaticCacheManager
from apps.core.models.sensitive_config import SensitiveConfig
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.http import FileResponse, HttpResponse, JsonResponse
from django.shortcuts import get_object_or_404, render
from django.views.generic import DetailView

from ..models.image_gallery import EXIF_ENG_CN, ImageGallery


class ImageDetailView(DetailView):
    model = ImageGallery

    context_object_name = 'image'
    slug_field = 'slug'
    slug_url_kwarg = 'slug'

    def get_template_names(self):
        # theme = getattr(self.request, 'current_theme', 'default') template
        theme = settings.THEME_NAME
        #文章个性模板>栏目内容模板>主题模型内容页templates/articles/article_item.html
        #themes/default/templates/articles/article_item.html是最后的容灾收段
        templates = []
        if self.object.template:
            templates.append(
                self.object.template.replace(
                    f'{settings.BASE_DIR}/templates/themes/', ''))
        if self.object.category.content_template:
            templates.append(
                self.object.category.content_template.replace(
                    f'{settings.BASE_DIR}/templates/themes/', ''))
        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"
        ])

        return templates

    def dispatch(self, request, *args, **kwargs):
        # 获取当前主题和备用模板路径
        theme = getattr(settings, 'THEME_NAME', 'default')
        templates = [
            f"themes/{theme}/templates/utils/403_restricted.html",
            "themes/default/templates/utils/403_restricted.html"
        ]
        # 先获取对象再校验权限
        self.object = self.get_object()
        if (self.object.staff_only or
                self.object.category.staff_only) and not request.user.is_staff:
            return render(request,
                          templates, {'message': '该内容仅限工作人员查看'},
                          status=403)
        if (self.object.allowed_groups.exists()
                and not self.object.allowed_groups.filter(
                    id__in=request.user.groups.all()).exists()) or (
                        self.object.category.allowed_groups.exists()
                        and not self.object.category.allowed_groups.filter(
                            id__in=request.user.groups.all()).exists()):
            return render(request,
                          templates, {'message': '您所在的用户组无权查看此内容'},
                          status=403)
        return super().dispatch(request, *args, **kwargs)

    def get_queryset(self):
        """基础查询集：仅限已发布状态"""
        return super().get_queryset().filter(
            status=ImageGallery.StatusChoices.REVIEW)

    def get_object(self, **kwargs):
        # 判断路径模式
        if 'pk' in self.kwargs:
            try:
                int(self.kwargs['pk'])
                return self._pk()
            except:
                return self._handle_hash()
        return super().get_object()

    def _pk(self):
        return get_object_or_404(ImageGallery, pk=self.kwargs['pk'], status=99)

    def _handle_hash(self):
        return get_object_or_404(ImageGallery,
                                 pk=int(unhash_id(self.kwargs['pk'])),
                                 status=99)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        obj = self.object
        obj_update_fields = []
        if not obj.previous_obj:
            previous_article = ImageGallery.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 = ImageGallery.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',
        ]
        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)
        exif_data = {
            '图像': {},
            'EXIF': {},
            'GPS': {},
            '其他': {},
            'Tag': {},
        }
        for k, v in obj.exif_info.items():
            k_cn = EXIF_ENG_CN[k]
            if 'Tag' in k:
                exif_data['Tag'][k_cn] = v
            elif 'GPS' in k:
                exif_data['GPS'][k_cn] = v
            elif 'EXIF' in k:
                exif_data['EXIF'][k_cn] = v
            elif 'Image' in k:
                exif_data['图像'][k_cn] = v
            else:
                exif_data['其他'][k_cn] = v
        img_small = obj.img_path('small')
        context.update({
            'obj': obj,
            'exif_data': exif_data,
            "img_small": img_small
            # 可扩展其他内容类型（wiki/downloads）
        })
        return context

    def get(self, request, *args, **kwargs):
        """自定义 GET 处理（可选）"""
        filename = request.path_info
        self.static_config = StaticSettings.get_solo()
        manager = StaticCacheManager(self.static_config.high_safe,
                                     self.static_config.static_tag)
        self.object = self.get_object()
        chack_small_img(self.object)
        # 获取静态内容

        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


from django.contrib.auth.decorators import login_required
from django.core.files.storage import default_storage

from ..tasks.generate_image import generate_image


@login_required
def download_image(request, pk, size):
    image = get_object_or_404(ImageGallery, pk=pk)

    # 动态构建目标路径
    target_path = image.processed_upload_to(size)

    # 优先检查已处理文件
    if default_storage.exists(target_path):
        # 强制下载的关键参数
        response = FileResponse(
            default_storage.open(target_path),
            as_attachment=True,  # 设置附件模式
            filename=os.path.basename(target_path)  # 指定下载文件名
        )
        # 显式设置内容类型（可选）
        response['Content-Type'] = 'application/octet-stream'
        return response

        # 触发异步生成
    threading.Thread(target=generate_image, args=(image.id, size),
                     daemon=True).start()

    # 首次请求返回 JSON 状态
    return JsonResponse(
        {
            'status': 'processing',
            'poll_url': f'/check-status/{pk}/{size}/'  # 轮询接口
        },
        status=202)


def chack_small_img(image):
    target_path = image.processed_upload_to('small')
    if default_storage.exists(target_path):
        pass
    else:
        threading.Thread(target=generate_image,
                         args=(image.id, 'small'),
                         daemon=True).start()
