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

from django.contrib.auth.decorators import login_required
from django.views.decorators.http import require_http_methods
from django.http import FileResponse, 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
from PAD_predict.models import PestDetectionRecord
import random


# PEST_MODEL_PATH = r'D:\eggplantshapeBS1\djangoProject\PAD_train\src\src\results\exp4\weights\best.pt'
PEST_MODEL_PATH = r'D:\eggplantshapeBS1\djangoProject\runs\evolve\evolution_latest\weights\best.pt'

_pest_model = None
_model_last_modified = 0


def get_pest_model():

    global _pest_model, _model_last_modified

    if not os.path.exists(PEST_MODEL_PATH):
        raise FileNotFoundError(f"找不到模型文件: {PEST_MODEL_PATH}")


    current_mtime = os.path.getmtime(PEST_MODEL_PATH)


    if _pest_model is None or current_mtime > _model_last_modified:
        print("\n" + "🔥" * 20)
        print(f"【热更新触发】检测到系统大脑已进化！正在将全新模型加载至内存...")
        _pest_model = YOLO(PEST_MODEL_PATH)
        _model_last_modified = current_mtime
        print("【热更新完成】紫睛灵 2.0 准备就绪！")
        print("🔥" * 20 + "\n")

    return _pest_model

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(["POST"])
@csrf_exempt
def upload_and_detect_pest(request):
    image_file = request.FILES.get('image')
    if image_file:

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


        if not longitude or longitude == 'undefined':
            longitude = random.uniform(118.8, 119.5)
            latitude = random.uniform(36.4, 37.1)

        fs = FileSystemStorage()
        filename = fs.save(image_file.name, image_file)
        image_path = fs.path(filename)

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

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

        result = results[0]
        label = result.names[int(result.boxes.cls[0])] if len(result.boxes.cls) > 0 else "Unknown"
        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)


        record = PestDetectionRecord.objects.create(
            user=request.user,
            operation_type="IMAGE",
            description=result.verbose(),
            result_path=result_filename,
            longitude=longitude,
            latitude=latitude
        )

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

@login_required
@require_http_methods(["POST"])
@csrf_exempt
def upload_video_and_detect_pest(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

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

    cap.release()
    out.release()


    PestDetectionRecord.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"])
@csrf_exempt
def camera_detect_pest(request):
    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

            model = get_pest_model()
            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()

    PestDetectionRecord.objects.create(
        user=request.user,
        operation_type="CAMERA",
        description="病虫害检测完成",
        result_path="暂无"
    )

    return StreamingHttpResponse(generate_frames(), content_type='text/event-stream')

# 确保文件顶部有引入 User 模型 (如果没有请加上)
from django.contrib.auth.models import User

# 导入你刚刚上传的高级模块
from .llm_expert import get_llm_prescription
from .fusion_engine import FusionDiagnosticAgent
# 从百科模块导入专家权重模型
from encyclopedia.models import DiseaseExpertWeight
from PAD_predict.models import PestDetectionRecord
# 确保文件顶部有定义 get_pest_model()
@csrf_exempt
def api_miniapp_pad_detect(request):

    if request.method == 'POST':
        try:
            print("--- 开始诊断流程 ---")
            image_file = request.FILES.get('image')
            user_id = request.POST.get('user_id')
            temp = float(request.POST.get('temp', 28.0))
            hum = float(request.POST.get('hum', 80.0))

            if not image_file:
                return JsonResponse({'code': 400, 'msg': '后端未收到文件'})

            # 保存图片
            fs = FileSystemStorage()
            filename = fs.save(image_file.name, image_file)
            image_path = fs.path(filename)
            print(f"图片已保存至: {image_path}")

            # 1. 视觉检测
            # 使用支持中文路径的读取方式
            image = cv2.imdecode(np.fromfile(image_path, dtype=np.uint8), cv2.IMREAD_COLOR)
            if image is None:
                os.remove(image_path)
                return JsonResponse({'code': 500, 'msg': '图片解码失败，请重新拍摄'})

            model = get_pest_model()
            results = model.predict(image)
            print("YOLO 推理完成")

            # 2. 逻辑分发：检测到目标 vs 未检测到
            if not results or len(results[0].boxes) == 0:
                # 【关键改动】如果没有检测到病害，不报错，而是返回“健康”
                label = "健康 (Healthy)"
                description = "未检测到明显病变特征"
                severity_percent = 0.0
                annotated_image = image  # 原图
                llm_text = "目前植株状态良好，建议保持正常的肥水管理，注意通风透光。"
                fusion_result = {"fused_score": 10, "env_status": "安全", "prediction_48h": 0}
            else:
                # 正常检测到病害
                result = results[0]
                label = result.names[int(result.boxes.cls[0])]
                description = result.verbose()
                annotated_image = result.plot()

                # 计算严重程度
                img_h, img_w, _ = image.shape
                box = result.boxes[0]
                box_area = float(box.xywh[0][2] * box.xywh[0][3])
                severity_percent = round((box_area / (img_w * img_h)) * 100, 2)

                # 3. 专家引擎
                try:
                    expert = DiseaseExpertWeight.objects.get(label_name=label)
                except:
                    class Mock:
                        optimum_temp = 28; optimum_hum = 85; temp_weight = 0.5; hum_weight = 0.5

                    expert = Mock()

                fusion_result = FusionDiagnosticAgent.calculate(severity_percent / 100, temp, hum, expert)
                llm_text = get_llm_prescription(label, temp, hum, severity_percent)

            # 4. 封装结果
            _, buffer = cv2.imencode('.jpg', annotated_image)
            img_base64 = "data:image/jpeg;base64," + base64.b64encode(buffer).decode('utf-8')

            os.remove(image_path)  # 清理
            print("--- 诊断成功返回 ---")

            return JsonResponse({
                'code': 200,
                'data': {
                    'label': label,
                    'result_text': description,
                    'image_base64': img_base64,
                    'severity': severity_percent,
                    'fusion_metrics': fusion_result,
                    'llm_expert_analysis': llm_text
                }
            })

        except Exception as e:
            import traceback
            traceback.print_exc()  # 在终端打印详细错误
            return JsonResponse({'code': 500, 'msg': f'服务器内部错误: {str(e)}'})

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