import os
import random
import re
from pathlib import Path

from apps.comments.models.comment import Comment
from apps.content.models import Category
from django import template
from django.conf import settings
from django.contrib.contenttypes.models import ContentType
from django.core.cache import cache

register = template.Library()


@register.simple_tag(takes_context=True)
def get_comments(context, obj):
    ct = ContentType.objects.get_for_model(obj)
    return Comment.objects.filter(content_type=ct,
                                  object_id=obj.pk,
                                  status=Comment.ApprovalStatus.APPROVED,
                                  is_deleted=False)


@register.inclusion_tag('includes/nav_cate_list.html', takes_context=True)
def tree_categorylist(context,
                      obj_id=None,
                      obj=None,
                      review_status=1,
                      nav_status=1):
    active = context.get('active')
    nodes = Category.get_tree_list(obj_id=obj_id,
                                   obj=obj,
                                   review_status=review_status,
                                   nav_status=nav_status)

    return locals()


@register.simple_tag
def nopic(cate=None):
    '''
    参数处理：添加了 cate=None参数，当有值时使用分类子目录
    路径逻辑：
    当 cate有值且对应目录存在时，使用 static/images/nopic/{cate}路径
    当 cate有值但目录不存在时，回退到基础路径
    当 cate为 None 时，维持原有逻辑
    缓存优化：为不同的分类生成不同的缓存键，避免数据混淆
    路径返回：根据是否存在有效分类，返回正确的图片路径
    '''
    # 根据cate参数生成缓存键
    cache_key = f"nopic_image_list_{cate}" if cate else "nopic_image_list"
    img_list = cache.get(cache_key)
    # 确定基础路径
    base_path = Path(settings.TEMPLATES_THEME_DIR) / "static/images/nopic"
    if not img_list:

        # 初始化最终使用的图片目录路径
        final_ku_path = base_path

        # 如果提供了cate参数，则尝试使用分类子目录
        if cate:
            category_path = base_path / str(cate)
            # 检查分类目录是否存在且非空（作为可选项，这里只检查存在性）
            if category_path.exists():
                final_ku_path = category_path
            # 如果分类目录不存在，则final_ku_path保持为base_path

        # 确保最终确定的目录存在
        if not final_ku_path.exists():
            os.makedirs(final_ku_path, exist_ok=True)

        # 从最终确定的目录中获取图片文件列表
        img_list = [
            file.name for file in final_ku_path.glob("*.*")
            if file.suffix.lower() in (".jpg", ".jpeg", ".png", ".gif",
                                       ".webp", ".svg", ".bmp", ".apng")
        ]

        # 如果没有找到图片，使用默认图片（确保default.jpg存在于base_path中）
        if not img_list:
            # 检查默认图片是否存在于基础路径
            default_image_path = base_path / "default.jpg"
            if not default_image_path.exists():
                # 如果默认图片也不存在，可以在此处创建或记录日志，但返回路径保持不变
                # 例如，可以复制一个默认图片到该位置，或者只是使用一个空列表
                # 这里我们选择保留一个固定的默认图片名，假设它最终会被解决
                pass
            img_list = ["default.jpg"]

        # 缓存24小时（86400秒）
        cache.set(cache_key, img_list, 86400)

    # 构建完整的图片路径 - 关键优化点
    # 随机选择一张图片
    selected_image = random.choice(img_list)

    # 判断图片实际存储的路径
    # 注意：这里我们无法直接判断图片文件存在于哪个目录，因为我们缓存的是文件名列表。
    # 因此，我们需要依赖之前的逻辑：如果cate目录存在且被使用，则图片应该在cate目录下；否则在基础目录下。
    # 由于缓存的存在，我们无法每次去检查文件是否存在，所以路径生成逻辑必须与上面确定final_ku_path的逻辑保持一致。

    # 重构：我们需要在确定使用哪个路径（base_path 或 category_path）时，记录一个标志。
    # 但由于缓存会丢失这个信息，我们需要一个更简洁的方法：

    # 最佳实践：在缓存中，我们不仅存储图片列表，还可以存储一个“路径标识”
    # 但为了最小化改动，我们采用更直接的方法：根据cate参数和目录存在性来决定路径前缀。
    # 让我们重新组织一下代码，将路径判断逻辑也缓存起来。

    # 由于这是一个较大的重构，这里提供一个更稳健的即时判断方法：
    # 如果cate有值，并且(base_path / str(cate)).exists()，则使用分类路径
    if cate and (base_path / str(cate)).exists():
        return f"/static/images/nopic/{cate}/{selected_image}"
    else:
        return f"/static/images/nopic/{selected_image}"


def is_valid_image_directory(directory_path):
    """
    严谨地判断一个目录是否是有效的图片目录。
    返回: 如果是有效图片目录则返回True，否则返回False。
    """
    path = Path(directory_path)

    # 条件1：路径存在且是一个目录
    if not (path.exists() and path.is_dir()):
        return False

    # 条件2：目录下包含可识别的图片文件
    for file_path in path.iterdir():
        if file_path.is_file():
            # 方法A：通过文件扩展名初步筛选（快速但可能不准确）
            if file_path.suffix.lower() in (".jpg", ".jpeg", ".png", ".gif",
                                            ".webp", ".svg", ".bmp", ".apng"):
                # 方法B：尝试用PIL打开文件进行验证（准确但稍慢）
                # try:
                #     with Image.open(file_path) as img:
                #         img.verify()  # 验证文件完整性
                #     # 如果能成功执行到此处，说明是一个有效图片
                #     return True
                # except (IOError, SyntaxError, Exception):
                #     # 如果文件损坏或不是图片，则跳过
                #     continue
                return True
    return False


def get_image_directory(cate=None):
    """
    获取图片目录路径
    根据cate参数返回对应的图片目录路径，提供容灾机制
    """
    # 确定基础路径
    base_dir = Path(
        settings.TEMPLATES_THEME_DIR) / "static/images/content_image"

    # 如果没有提供cate参数，直接使用基础路径
    if not cate:
        img_dir = base_dir
        is_category_dir = False
    else:
        # 如果提供了cate参数，尝试使用分类子目录
        category_dir = base_dir / str(cate)
        # 检查分类目录是否存在且包含图片文件
        if is_valid_image_directory(category_dir):  # 调用上面定义的严谨判断函数:
            img_dir = category_dir
            is_category_dir = True
        else:
            img_dir = base_dir
            is_category_dir = False

    # 确保目录存在
    if not img_dir.exists():
        os.makedirs(img_dir, exist_ok=True)

    return img_dir, base_dir, is_category_dir


@register.simple_tag
def random_content_image(content=None, get_img=True, cate=None):
    '''
    标签逻辑：
    检查content有没有值传入，如果没有则直接随机出张图
    content有值，如果有img且get_img为True则出图，否则无图
    cate参数：当cate有值时，使用分类子目录，不存在时回退到基础目录
    
    参数说明：
    - content: 内容文本，用于检测是否包含图片
    - get_img: 是否获取图片，默认为True
    - cate: 分类目录名称，用于指定图片子目录（提供容灾机制）
    '''
    # 先检测content中的img标签
    has_img = bool(re.search(r'<img[^>]+>',
                             str(content))) if content else False

    # 根据cate参数生成缓存键
    cache_key = f"random_content_image_list_{cate}" if cate else "random_content_image_list"

    # 获取图片目录（包含容灾逻辑）
    img_dir, base_dir, is_category_dir = get_image_directory(cate)

    if content:
        if has_img and get_img:
            # 只有需要图片时才加载图片列表
            img_list = cache.get(cache_key)
            if not img_list:
                if img_dir.exists():
                    img_list = [
                        # 根据是否为分类目录构建正确的路径
                        f"/static/images/content_image/{cate}/{file.name}"
                        if is_category_dir else
                        f"/static/images/content_image/{file.name}"
                        for file in img_dir.glob("*.*")
                        if file.suffix.lower() in (".jpg", ".jpeg", ".png",
                                                   ".gif", ".webp", ".svg",
                                                   ".bmp", ".apng")
                    ]
                    if img_list:
                        cache.set(cache_key, img_list, 86400)

            return random.choice(img_list) if img_list else ''
        else:
            return ''
    else:
        # 只有需要图片时才加载图片列表
        img_list = cache.get(cache_key)
        if not img_list:
            if img_dir.exists():
                img_list = [
                    # 根据是否为分类目录构建正确的路径
                    f"/static/images/content_image/{cate}/{file.name}"
                    if is_category_dir else
                    f"/static/images/content_image/{file.name}"
                    for file in img_dir.glob("*.*")
                    if file.suffix.lower() in (".jpg", ".jpeg", ".png", ".gif",
                                               ".webp", ".svg", ".bmp",
                                               ".apng")
                ]
                if img_list:
                    cache.set(cache_key, img_list, 86400)

        return random.choice(img_list) if img_list else ''
