# 多媒体管理 API 视图
# 提供图片上传、管理、删除等功能

import os
import uuid
import mimetypes
import logging
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.http import JsonResponse, HttpResponseForbidden
from django.views.decorators.http import require_http_methods
from django.core.paginator import Paginator
from PIL import Image

from blog.models_media import MediaFile, MediaFolder, MediaFileFolder
from djangoblog.utils import get_sha256

logger = logging.getLogger(__name__)


# ==================== 文件上传 API ====================

@login_required
@require_http_methods(["POST"])
def upload_media_api(request):
    """
    上传媒体文件 API

    POST 参数：
        - file: 上传的文件
        - folder_id: 文件夹ID（可选）
        - description: 文件描述（可选）
        - is_public: 是否公开（可选，默认True）

    返回：
        JSON: {success: true, file: {...}}
    """
    try:
        # 检查是否有文件
        if 'file' not in request.FILES:
            return JsonResponse({
                'success': False,
                'message': '没有上传文件'
            }, status=400)

        uploaded_file = request.FILES['file']
        folder_id = request.POST.get('folder_id')
        description = request.POST.get('description', '')
        is_public = request.POST.get('is_public', 'true').lower() == 'true'

        # 验证文件大小（默认最大10MB）
        max_size = getattr(settings, 'MAX_UPLOAD_SIZE', 10 * 1024 * 1024)
        if uploaded_file.size > max_size:
            return JsonResponse({
                'success': False,
                'message': f'文件大小超过限制（最大{max_size // (1024*1024)}MB）'
            }, status=400)

        # 计算文件哈希
        file_hash = MediaFile.get_file_hash(uploaded_file)

        # 检查是否已存在相同文件
        existing_file = MediaFile.check_duplicate(file_hash)
        if existing_file:
            # 如果已存在，直接返回已有文件
            return JsonResponse({
                'success': True,
                'message': '文件已存在，使用已有文件',
                'file': _serialize_media_file(existing_file),
                'is_duplicate': True
            })

        # 判断文件类型
        original_filename = uploaded_file.name
        file_ext = os.path.splitext(original_filename)[1].lower()
        mime_type = uploaded_file.content_type or mimetypes.guess_type(original_filename)[0] or 'application/octet-stream'

        # 判断是否为图片
        image_extensions = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp']
        is_image = file_ext in image_extensions

        # 生成存储文件名
        from django.utils import timezone
        timestr = timezone.now().strftime('%Y/%m/%d')
        stored_filename = f"{uuid.uuid4().hex}{file_ext}"

        # 确定存储路径
        file_type = 'image' if is_image else 'files'
        base_dir = os.path.join(settings.STATICFILES, file_type, timestr)
        if not os.path.exists(base_dir):
            os.makedirs(base_dir)

        # 保存文件
        save_path = os.path.join(base_dir, stored_filename)
        with open(save_path, 'wb+') as destination:
            for chunk in uploaded_file.chunks():
                destination.write(chunk)

        # 相对路径
        relative_path = os.path.join(file_type, timestr, stored_filename).replace('\\', '/')

        # 获取图片尺寸
        width, height = None, None
        if is_image:
            try:
                with Image.open(save_path) as img:
                    width, height = img.size

                    # 如果图片太大，进行压缩
                    max_dimension = 2000
                    if width > max_dimension or height > max_dimension:
                        img.thumbnail((max_dimension, max_dimension), Image.Resampling.LANCZOS)
                        img.save(save_path, quality=85, optimize=True)
                        width, height = img.size
                    else:
                        # 优化图片
                        img.save(save_path, quality=85, optimize=True)

            except Exception as e:
                logger.error(f"处理图片失败: {e}", exc_info=True)

        # 创建数据库记录
        media_file = MediaFile.objects.create(
            original_filename=original_filename,
            stored_filename=stored_filename,
            file_type='image' if is_image else 'file',
            file_size=uploaded_file.size,
            file_hash=file_hash,
            mime_type=mime_type,
            file_path=relative_path,
            uploader=request.user,
            width=width,
            height=height,
            description=description,
            is_public=is_public
        )

        # 生成缩略图
        if is_image:
            media_file.generate_thumbnail()

        # 添加到文件夹
        if folder_id:
            try:
                folder = MediaFolder.objects.get(id=folder_id, owner=request.user)
                MediaFileFolder.objects.create(file=media_file, folder=folder)
            except MediaFolder.DoesNotExist:
                pass

        return JsonResponse({
            'success': True,
            'message': '上传成功',
            'file': _serialize_media_file(media_file)
        })

    except Exception as e:
        logger.error(f"上传文件失败: {e}", exc_info=True)
        return JsonResponse({
            'success': False,
            'message': f'上传失败: {str(e)}'
        }, status=500)


@login_required
@require_http_methods(["GET"])
def list_media_api(request):
    """
    获取媒体文件列表 API

    GET 参数：
        - page: 页码（可选，默认1）
        - page_size: 每页数量（可选，默认20）
        - file_type: 文件类型筛选（可选：image/file）
        - folder_id: 文件夹ID（可选）
        - search: 搜索关键词（可选）

    返回：
        JSON: {success: true, files: [...], total: xxx, page: xxx}
    """
    try:
        page = int(request.GET.get('page', 1))
        page_size = int(request.GET.get('page_size', 20))
        file_type = request.GET.get('file_type')
        folder_id = request.GET.get('folder_id')
        search = request.GET.get('search', '').strip()

        # 基础查询（只显示用户自己的文件）
        queryset = MediaFile.objects.filter(uploader=request.user)

        # 文件类型筛选
        if file_type in ['image', 'file']:
            queryset = queryset.filter(file_type=file_type)

        # 文件夹筛选
        if folder_id:
            try:
                folder = MediaFolder.objects.get(id=folder_id, owner=request.user)
                file_ids = MediaFileFolder.objects.filter(folder=folder).values_list('file_id', flat=True)
                queryset = queryset.filter(id__in=file_ids)
            except MediaFolder.DoesNotExist:
                pass

        # 搜索
        if search:
            queryset = queryset.filter(original_filename__icontains=search)

        # 排序
        queryset = queryset.order_by('-upload_time')

        # 分页
        paginator = Paginator(queryset, page_size)
        page_obj = paginator.get_page(page)

        files_data = [_serialize_media_file(f) for f in page_obj]

        return JsonResponse({
            'success': True,
            'files': files_data,
            'total': paginator.count,
            'page': page,
            'page_size': page_size,
            'total_pages': paginator.num_pages
        })

    except Exception as e:
        logger.error(f"获取文件列表失败: {e}", exc_info=True)
        return JsonResponse({
            'success': False,
            'message': f'获取失败: {str(e)}'
        }, status=500)


@login_required
@require_http_methods(["DELETE"])
def delete_media_api(request):
    """
    删除媒体文件 API

    DELETE 参数（JSON）：
        - file_id: 文件ID

    返回：
        JSON: {success: true, message: xxx}
    """
    try:
        import json
        data = json.loads(request.body)
        file_id = data.get('file_id')

        if not file_id:
            return JsonResponse({
                'success': False,
                'message': '缺少 file_id 参数'
            }, status=400)

        # 获取文件（只能删除自己的文件）
        try:
            media_file = MediaFile.objects.get(id=file_id, uploader=request.user)
        except MediaFile.DoesNotExist:
            return JsonResponse({
                'success': False,
                'message': '文件不存在或无权限删除'
            }, status=404)

        # 检查引用计数
        if media_file.reference_count > 0:
            return JsonResponse({
                'success': False,
                'message': f'文件正被{media_file.reference_count}处引用，无法删除'
            }, status=400)

        filename = media_file.original_filename
        media_file.delete()

        return JsonResponse({
            'success': True,
            'message': f'已删除文件：{filename}'
        })

    except Exception as e:
        logger.error(f"删除文件失败: {e}", exc_info=True)
        return JsonResponse({
            'success': False,
            'message': f'删除失败: {str(e)}'
        }, status=500)


@login_required
@require_http_methods(["POST"])
def update_media_api(request):
    """
    更新媒体文件信息 API

    POST 参数（JSON）：
        - file_id: 文件ID
        - description: 描述（可选）
        - is_public: 是否公开（可选）

    返回：
        JSON: {success: true, file: {...}}
    """
    try:
        import json
        data = json.loads(request.body)
        file_id = data.get('file_id')

        if not file_id:
            return JsonResponse({
                'success': False,
                'message': '缺少 file_id 参数'
            }, status=400)

        # 获取文件
        try:
            media_file = MediaFile.objects.get(id=file_id, uploader=request.user)
        except MediaFile.DoesNotExist:
            return JsonResponse({
                'success': False,
                'message': '文件不存在或无权限修改'
            }, status=404)

        # 更新字段
        if 'description' in data:
            media_file.description = data['description']

        if 'is_public' in data:
            media_file.is_public = data['is_public']

        media_file.save()

        return JsonResponse({
            'success': True,
            'message': '更新成功',
            'file': _serialize_media_file(media_file)
        })

    except Exception as e:
        logger.error(f"更新文件失败: {e}", exc_info=True)
        return JsonResponse({
            'success': False,
            'message': f'更新失败: {str(e)}'
        }, status=500)


# ==================== 文件夹管理 API ====================

@login_required
@require_http_methods(["POST"])
def create_folder_api(request):
    """创建文件夹"""
    try:
        import json
        data = json.loads(request.body)
        name = data.get('name', '').strip()
        parent_id = data.get('parent_id')
        description = data.get('description', '')

        if not name:
            return JsonResponse({
                'success': False,
                'message': '文件夹名称不能为空'
            }, status=400)

        # 获取父文件夹
        parent = None
        if parent_id:
            try:
                parent = MediaFolder.objects.get(id=parent_id, owner=request.user)
            except MediaFolder.DoesNotExist:
                return JsonResponse({
                    'success': False,
                    'message': '父文件夹不存在'
                }, status=404)

        # 创建文件夹
        folder = MediaFolder.objects.create(
            name=name,
            parent=parent,
            owner=request.user,
            description=description
        )

        return JsonResponse({
            'success': True,
            'message': '创建成功',
            'folder': {
                'id': folder.id,
                'name': folder.name,
                'full_path': folder.get_full_path(),
                'parent_id': folder.parent_id,
                'created_time': folder.created_time.strftime('%Y-%m-%d %H:%M:%S'),
                'description': folder.description
            }
        })

    except Exception as e:
        logger.error(f"创建文件夹失败: {e}", exc_info=True)
        return JsonResponse({
            'success': False,
            'message': f'创建失败: {str(e)}'
        }, status=500)


@login_required
@require_http_methods(["GET"])
def list_folders_api(request):
    """获取文件夹列表"""
    try:
        folders = MediaFolder.objects.filter(owner=request.user).order_by('name')

        folders_data = []
        for folder in folders:
            folders_data.append({
                'id': folder.id,
                'name': folder.name,
                'full_path': folder.get_full_path(),
                'parent_id': folder.parent_id,
                'created_time': folder.created_time.strftime('%Y-%m-%d %H:%M:%S'),
                'files_count': folder.file_relations.count()
            })

        return JsonResponse({
            'success': True,
            'folders': folders_data
        })

    except Exception as e:
        logger.error(f"获取文件夹列表失败: {e}", exc_info=True)
        return JsonResponse({
            'success': False,
            'message': f'获取失败: {str(e)}'
        }, status=500)


# ==================== 工具函数 ====================

def _serialize_media_file(media_file):
    """序列化媒体文件对象"""
    return {
        'id': media_file.id,
        'original_filename': media_file.original_filename,
        'file_type': media_file.file_type,
        'file_size': media_file.file_size,
        'file_size_readable': _format_file_size(media_file.file_size),
        'mime_type': media_file.mime_type,
        'url': media_file.get_absolute_url(),
        'thumbnail_url': media_file.get_thumbnail_url(),
        'width': media_file.width,
        'height': media_file.height,
        'upload_time': media_file.upload_time.strftime('%Y-%m-%d %H:%M:%S'),
        'description': media_file.description,
        'is_public': media_file.is_public,
        'reference_count': media_file.reference_count
    }


def _format_file_size(size_bytes):
    """格式化文件大小"""
    for unit in ['B', 'KB', 'MB', 'GB']:
        if size_bytes < 1024.0:
            return f"{size_bytes:.1f} {unit}"
        size_bytes /= 1024.0
    return f"{size_bytes:.1f} TB"
