# 多媒体管理模型
# 提供图片、文件的上传、管理和优化功能

import os
from django.conf import settings
from django.db import models
from django.utils.timezone import now
from django.utils.translation import gettext_lazy as _
from PIL import Image
import hashlib


class MediaFile(models.Model):
    """
    媒体文件模型
    存储所有上传的图片和文件信息
    """
    FILE_TYPE_CHOICES = [
        ('image', '图片'),
        ('file', '文件'),
    ]

    # 文件名（原始文件名）
    original_filename = models.CharField('原始文件名', max_length=255)

    # 存储文件名（实际存储的唯一文件名）
    stored_filename = models.CharField('存储文件名', max_length=255, unique=True)

    # 文件类型（图片或普通文件）
    file_type = models.CharField('文件类型', max_length=10, choices=FILE_TYPE_CHOICES)

    # 文件大小（字节）
    file_size = models.BigIntegerField('文件大小')

    # 文件MD5哈希（用于去重）
    file_hash = models.CharField('文件哈希', max_length=32, db_index=True)

    # MIME类型
    mime_type = models.CharField('MIME类型', max_length=100)

    # 文件路径（相对路径）
    file_path = models.CharField('文件路径', max_length=500)

    # 上传用户
    uploader = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        verbose_name='上传者',
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='uploaded_files'
    )

    # 上传时间
    upload_time = models.DateTimeField('上传时间', default=now, db_index=True)

    # 图片专属字段
    # 图片宽度
    width = models.IntegerField('宽度', null=True, blank=True)

    # 图片高度
    height = models.IntegerField('高度', null=True, blank=True)

    # 缩略图路径
    thumbnail_path = models.CharField('缩略图路径', max_length=500, blank=True)

    # 描述/备注
    description = models.TextField('描述', blank=True)

    # 是否公开（私有文件只有上传者可访问）
    is_public = models.BooleanField('是否公开', default=True)

    # 引用计数（被多少篇文章引用）
    reference_count = models.IntegerField('引用次数', default=0)

    class Meta:
        ordering = ['-upload_time']
        verbose_name = '媒体文件'
        verbose_name_plural = '媒体文件'
        indexes = [
            models.Index(fields=['file_type', '-upload_time'], name='media_type_time_idx'),
            models.Index(fields=['uploader', '-upload_time'], name='media_uploader_time_idx'),
            models.Index(fields=['file_hash'], name='media_hash_idx'),
        ]

    def __str__(self):
        return self.original_filename

    def get_absolute_url(self):
        """获取文件的访问URL"""
        from django.templatetags.static import static
        return static(self.file_path)

    def get_thumbnail_url(self):
        """获取缩略图URL"""
        if self.thumbnail_path:
            from django.templatetags.static import static
            return static(self.thumbnail_path)
        return self.get_absolute_url()

    def get_file_extension(self):
        """获取文件扩展名"""
        return os.path.splitext(self.original_filename)[1].lower()

    def is_image(self):
        """判断是否为图片"""
        return self.file_type == 'image'

    def delete(self, *args, **kwargs):
        """删除文件时同时删除物理文件"""
        # 删除主文件
        full_path = os.path.join(settings.STATICFILES, self.file_path)
        if os.path.exists(full_path):
            try:
                os.remove(full_path)
            except Exception as e:
                import logging
                logging.error(f"删除文件失败 {full_path}: {e}")

        # 删除缩略图
        if self.thumbnail_path:
            thumb_path = os.path.join(settings.STATICFILES, self.thumbnail_path)
            if os.path.exists(thumb_path):
                try:
                    os.remove(thumb_path)
                except Exception as e:
                    import logging
                    logging.error(f"删除缩略图失败 {thumb_path}: {e}")

        super().delete(*args, **kwargs)

    @classmethod
    def get_file_hash(cls, file_content):
        """计算文件MD5哈希"""
        md5 = hashlib.md5()
        for chunk in file_content.chunks():
            md5.update(chunk)
        return md5.hexdigest()

    @classmethod
    def check_duplicate(cls, file_hash):
        """检查是否已存在相同文件"""
        return cls.objects.filter(file_hash=file_hash).first()

    def generate_thumbnail(self, max_size=(300, 300)):
        """生成缩略图"""
        if not self.is_image():
            return False

        try:
            full_path = os.path.join(settings.STATICFILES, self.file_path)
            if not os.path.exists(full_path):
                return False

            # 打开图片
            img = Image.open(full_path)

            # 转换RGBA为RGB（处理PNG透明背景）
            if img.mode in ('RGBA', 'LA', 'P'):
                background = Image.new('RGB', img.size, (255, 255, 255))
                if img.mode == 'P':
                    img = img.convert('RGBA')
                background.paste(img, mask=img.split()[-1] if img.mode == 'RGBA' else None)
                img = background

            # 生成缩略图
            img.thumbnail(max_size, Image.Resampling.LANCZOS)

            # 保存缩略图
            thumb_filename = f"thumb_{self.stored_filename}"
            thumb_dir = os.path.dirname(full_path)
            thumb_path = os.path.join(thumb_dir, thumb_filename)

            img.save(thumb_path, quality=85, optimize=True)

            # 更新缩略图路径
            self.thumbnail_path = os.path.join(
                os.path.dirname(self.file_path),
                thumb_filename
            )
            self.save(update_fields=['thumbnail_path'])

            return True

        except Exception as e:
            import logging
            logging.error(f"生成缩略图失败: {e}", exc_info=True)
            return False


class MediaFolder(models.Model):
    """
    媒体文件夹模型
    用于组织和分类媒体文件
    """
    # 文件夹名称
    name = models.CharField('文件夹名称', max_length=100)

    # 父文件夹（支持嵌套）
    parent = models.ForeignKey(
        'self',
        verbose_name='父文件夹',
        on_delete=models.CASCADE,
        null=True,
        blank=True,
        related_name='subfolders'
    )

    # 所有者
    owner = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        verbose_name='所有者',
        on_delete=models.CASCADE,
        related_name='media_folders'
    )

    # 创建时间
    created_time = models.DateTimeField('创建时间', default=now)

    # 描述
    description = models.TextField('描述', blank=True)

    class Meta:
        ordering = ['name']
        verbose_name = '媒体文件夹'
        verbose_name_plural = '媒体文件夹'
        unique_together = [['name', 'parent', 'owner']]

    def __str__(self):
        return self.get_full_path()

    def get_full_path(self):
        """获取完整路径"""
        if self.parent:
            return f"{self.parent.get_full_path()}/{self.name}"
        return self.name

    def get_files_count(self):
        """获取文件夹中的文件数量"""
        return self.files.count()


class MediaFileFolder(models.Model):
    """
    媒体文件和文件夹的关联表
    支持一个文件属于多个文件夹
    """
    file = models.ForeignKey(
        MediaFile,
        on_delete=models.CASCADE,
        related_name='folder_relations'
    )

    folder = models.ForeignKey(
        MediaFolder,
        on_delete=models.CASCADE,
        related_name='file_relations'
    )

    added_time = models.DateTimeField('添加时间', default=now)

    class Meta:
        unique_together = [['file', 'folder']]
        verbose_name = '文件-文件夹关联'
        verbose_name_plural = '文件-文件夹关联'

    def __str__(self):
        return f"{self.file.original_filename} -> {self.folder.name}"
