import json
import subprocess
import cv2
import numpy as np
import os
import base64
import tempfile

from django.contrib.auth.decorators import login_required

from app01.models import OperationRecord

from django.views.decorators.http import require_http_methods
from django.http import FileResponse
from django.core.files.storage import FileSystemStorage
from django.http import JsonResponse, HttpResponse, StreamingHttpResponse
from django.views.decorators.csrf import csrf_exempt
from django.core.files.storage import FileSystemStorage
from ultralytics import YOLO

from djangoProject import settings

# 指定已经训练好的YOLO模型路径
MODEL_PATH = r'D:\eggplantshapeBS\djangoProject\train\src\src\results\exp2\weights\best.pt'
model = YOLO(MODEL_PATH)

def download_file(request, filename):

    file_path = os.path.join(settings.MEDIA_ROOT, filename)
    if os.path.exists(file_path):

        with open(file_path, 'rb') as f:
            response = FileResponse(f, content_type="application/octet-stream")
            response['Content-Disposition'] = f'attachment; filename="{filename}"'
            return response
    else:
        from django.http import HttpResponseNotFound
        return HttpResponseNotFound("File not found")

@login_required
@require_http_methods(["GET", "POST"])
@csrf_exempt
def upload_and_detect(request):
    if request.method == 'POST':
        image_file = request.FILES.get('image')
        if image_file:
            fs = FileSystemStorage()
            filename = fs.save(image_file.name, image_file)
            image_path = fs.path(filename)

            image = cv2.imread(image_path)
            results = model.predict(image)

            if not results:
                return JsonResponse({'error': 'No detections found'}, status=400)

            description = results[0].verbose()

            result = results[0]
            annotated_image = result.plot()

            _, buffer = cv2.imencode('.jpg', annotated_image)
            result_image_base64 = base64.b64encode(buffer).decode('utf-8')

            result_filename = f"detected_{filename}"
            result_path = fs.path(result_filename)
            cv2.imwrite(result_path, annotated_image)

            OperationRecord.objects.create(
                user=request.user,
                operation_type="IMAGE",
                description=description,
                result_path=result_filename
            )

            os.remove(image_path)

            result = results[0]
            label = result.names[int(result.boxes.cls[0])] if len(result.boxes.cls) > 0 else "Unknown"
            import random

            lon = request.POST.get('longitude')
            lat = request.POST.get('latitude')

            if not lon or lon == 'undefined':
                lon = random.uniform(117.0, 119.0)
                lat = random.uniform(36.0, 37.0)
            record = OperationRecord.objects.create(
                user=request.user,
                operation_type="IMAGE",
                description=results[0].verbose(),
                result_path=result_filename,
                longitude=lon,
                latitude=lat
            )

            return JsonResponse({
                'status': 'success',
                'resultImage': result_image_base64,
                'record_id': record.id,
                'label': label
            })
        else:
            return JsonResponse({'error': 'No image file provided'}, status=400)
    else:
        return JsonResponse({'error': 'Invalid request method'}, status=500)

@login_required
@require_http_methods(["POST"])
@csrf_exempt
def upload_video_and_detect(request):
    video_file = request.FILES.get('video')
    if not video_file:
        return JsonResponse({'error': 'No video file provided'}, status=400)

    with tempfile.NamedTemporaryFile(delete=False, suffix=os.path.splitext(video_file.name)[1]) as temp_file:
        temp_video_path = temp_file.name
        for chunk in video_file.chunks():
            temp_file.write(chunk)

    cap = cv2.VideoCapture(temp_video_path)
    if not cap.isOpened():
        return JsonResponse({'error': 'Failed to open video file'}, status=400)

    fps = cap.get(cv2.CAP_PROP_FPS)
    width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))

    output_video_path = tempfile.mktemp(suffix='.mp4')
    fourcc = cv2.VideoWriter_fourcc(*'avc1')
    out = cv2.VideoWriter(output_video_path, fourcc, fps, (width, height))

    while True:
        ret, frame = cap.read()
        if not ret:
            break

        results = model.predict(frame)
        if results:
            result = results[0]
            annotated_frame = result.plot()
            out.write(annotated_frame)

    cap.release()
    out.release()

    OperationRecord.objects.create(
        user=request.user,
        operation_type="VIDEO",
        description="视频检测完成",
        result_path=f"detected_{video_file.name}"
    )

    os.remove(temp_video_path)

    response = HttpResponse(open(output_video_path, 'rb'), content_type='video/mp4')
    response['Content-Disposition'] = 'attachment; filename="detected_video.mp4"'
    return response

@login_required
@require_http_methods(["GET", "POST"])
@csrf_exempt
def camera_detect(request):
    if request.method == 'GET':
        def generate_frames():
            cap = cv2.VideoCapture(0)
            if not cap.isOpened():
                yield f"data: {json.dumps({'error': 'Failed to open camera'})}\n\n"
                return

            while True:
                ret, frame = cap.read()
                if not ret:
                    break

                results = model.predict(frame)
                result = results[0]
                annotated_frame = result.plot()

                _, buffer = cv2.imencode('.jpg', annotated_frame)
                frame_base64 = base64.b64encode(buffer).decode('utf-8')

                yield f"data: {json.dumps({'frame': frame_base64})}\n\n"

            cap.release()

        OperationRecord.objects.create(
            user=request.user,
            operation_type="CAMERA",
            description="摄像头检测完成",
            result_path="暂无"
        )

        return StreamingHttpResponse(generate_frames(), content_type='text/event-stream')
    else:
        return JsonResponse({'error': 'Invalid request method'}, status=500)


# 确保文件顶部有这个导入（如果没有请加上）：
from django.contrib.auth.models import User


# === 以下为新增的小程序专属接口 ===
@csrf_exempt
def api_miniapp_detect(request):
    """小程序专属：图像上传与YOLO检测接口"""
    if request.method == 'POST':
        try:
            image_file = request.FILES.get('image')
            user_id = request.POST.get('user_id')  # 接收小程序传来的用户ID

            if not image_file:
                return JsonResponse({'code': 400, 'msg': '未接收到图片'})

            # 1. 查找对应的用户
            user = None
            if user_id:
                user = User.objects.filter(id=user_id).first()

            # 2. 保存上传的图片
            fs = FileSystemStorage()
            filename = fs.save(image_file.name, image_file)
            image_path = fs.path(filename)

            # 3. 使用你的 YOLO 模型进行预测
            image = cv2.imread(image_path)
            results = model.predict(image)

            if not results:
                os.remove(image_path)
                return JsonResponse({'code': 400, 'msg': '未检测到目标'})

            # 4. 获取预测结果并画框
            result = results[0]
            description = result.verbose()
            annotated_image = result.plot()

            # 5. 将画好框的图片转为 Base64（这样可以直接发给小程序显示，不需要返回 URL）
            _, buffer = cv2.imencode('.jpg', annotated_image)
            result_image_base64 = base64.b64encode(buffer).decode('utf-8')

            # 6. 保存检测结果图片
            result_filename = f"detected_{filename}"
            result_path = fs.path(result_filename)
            cv2.imwrite(result_path, annotated_image)

            # 7. 写入数据库 OperationRecord
            if user:
                OperationRecord.objects.create(
                    user=user,
                    operation_type="IMAGE",
                    description=description,
                    result_path=result_filename
                )

            os.remove(image_path)  # 删除原图节省空间

            label = result.names[int(result.boxes.cls[0])] if len(result.boxes.cls) > 0 else "未知"

            # 8. 返回成功数据
            return JsonResponse({
                'code': 200,
                'msg': '检测成功',
                'data': {
                    'result_text': description,
                    'label': label,
                    # 加上 data:image 前缀，小程序 <image> 标签就能直接渲染 base64 字符串
                    'image_base64': f"data:image/jpeg;base64,{result_image_base64}"
                }
            })

        except Exception as e:
            import traceback
            traceback.print_exc()
            return JsonResponse({'code': 500, 'msg': f'服务器内部错误: {str(e)}'})

    return JsonResponse({'code': 405, 'msg': '仅支持 POST 请求'})