from drf_spectacular.utils import OpenApiExample, extend_schema from rest_framework import status from rest_framework.response import Response from rest_framework.views import APIView from config.openapi import ( build_envelope_serializer, build_response, ) from .models import IrrigationMethod from .serializers import ( IrrigationMethodSerializer, IrrigationRecommendRequestSerializer, ) IrrigationMethodListResponseSerializer = build_envelope_serializer( "IrrigationMethodListResponseSerializer", IrrigationMethodSerializer, many=True, ) IrrigationMethodDetailResponseSerializer = build_envelope_serializer( "IrrigationMethodDetailResponseSerializer", IrrigationMethodSerializer, ) IrrigationValidationErrorSerializer = build_envelope_serializer( "IrrigationValidationErrorSerializer", data_required=False, allow_null=True, ) IrrigationRecommendResponseSerializer = build_envelope_serializer( "IrrigationRecommendResponseSerializer", data_schema=None, ) class IrrigationMethodListCreateView(APIView): """لیست تمام روش‌های آبیاری و ایجاد روش جدید.""" @extend_schema( tags=["Irrigation"], summary="لیست روش‌های آبیاری", description="لیست تمام روش‌های آبیاری ذخیره‌شده را برمی‌گرداند.", responses={ 200: build_response( IrrigationMethodListResponseSerializer, "لیست روش‌های آبیاری ذخیره‌شده.", ), }, ) def get(self, request): methods = IrrigationMethod.objects.all() serializer = IrrigationMethodSerializer(methods, many=True) return Response( {"code": 200, "msg": "success", "data": serializer.data}, status=status.HTTP_200_OK, ) @extend_schema( tags=["Irrigation"], summary="ایجاد روش آبیاری جدید", description="یک روش آبیاری جدید ایجاد می‌کند.", request=IrrigationMethodSerializer, responses={ 201: build_response( IrrigationMethodDetailResponseSerializer, "روش آبیاری جدید با موفقیت ایجاد شد.", ), 400: build_response( IrrigationValidationErrorSerializer, "داده ورودی نامعتبر است.", ), }, examples=[ OpenApiExample( "نمونه درخواست", value={ "name": "آبیاری قطره‌ای", "category": "موضعی", "description": "آبیاری با دبی کم و فشار مناسب", "water_efficiency_percent": 90.0, "water_pressure_required": "۱-۲ اتمسفر", "flow_rate": "۲-۸ لیتر در ساعت", "coverage_area": "بسته به طراحی سیستم", "soil_type": "تمام انواع خاک", "climate_suitability": "گرم و خشک", }, request_only=True, ), ], ) def post(self, request): serializer = IrrigationMethodSerializer(data=request.data) if not serializer.is_valid(): return Response( {"code": 400, "msg": "داده نامعتبر.", "data": serializer.errors}, status=status.HTTP_400_BAD_REQUEST, ) serializer.save() return Response( {"code": 201, "msg": "success", "data": serializer.data}, status=status.HTTP_201_CREATED, ) class IrrigationRecommendView(APIView): """ توصیه آبیاری به صورت مستقیم. POST با sensor_uuid، plant_name، growth_stage، irrigation_method_name. اطلاعات گیاه از plant app و روش آبیاری از irrigation app دریافت می‌شود. """ @extend_schema( tags=["Irrigation Recommendation"], summary="درخواست توصیه آبیاری", description=( "داده‌های سنسور، گیاه و روش آبیاری را دریافت کرده و " "توصیه آبیاری را مستقیم برمی‌گرداند. " "اطلاعات گیاه از جدول Plant و روش آبیاری از جدول IrrigationMethod بارگذاری می‌شود. " "محاسبات ET₀ و ETc با مدل FAO-56 در بک‌اند انجام می‌شود و مدل زبانی فقط توضیح برنامه آبیاری را تولید می‌کند." ), request=IrrigationRecommendRequestSerializer, responses={ 200: build_response( IrrigationRecommendResponseSerializer, "توصیه آبیاری با موفقیت تولید شد.", ), 400: build_response( IrrigationValidationErrorSerializer, "پارامتر ورودی نامعتبر است.", ), 500: build_response( IrrigationValidationErrorSerializer, "خطا در تولید توصیه آبیاری.", ), }, examples=[ OpenApiExample( "نمونه درخواست", value={ "sensor_uuid": "550e8400-e29b-41d4-a716-446655440000", "plant_name": "گوجه‌فرنگی", "growth_stage": "گلدهی", "irrigation_method_name": "آبیاری قطره‌ای", }, request_only=True, ), ], ) def post(self, request): from rag.services.irrigation import get_irrigation_recommendation serializer = IrrigationRecommendRequestSerializer(data=request.data) if not serializer.is_valid(): return Response( {"code": 400, "msg": "داده نامعتبر.", "data": serializer.errors}, status=status.HTTP_400_BAD_REQUEST, ) validated = serializer.validated_data sensor_uuid = validated["sensor_uuid"] plant_name = validated.get("plant_name") growth_stage = validated.get("growth_stage") irrigation_method_name = validated.get("irrigation_method_name") query = validated.get("query") try: result = get_irrigation_recommendation( sensor_uuid=sensor_uuid, plant_name=plant_name, growth_stage=growth_stage, irrigation_method_name=irrigation_method_name, query=query, ) except Exception as exc: return Response( {"code": 500, "msg": f"خطا در تولید توصیه آبیاری: {exc}", "data": None}, status=status.HTTP_500_INTERNAL_SERVER_ERROR, ) return Response( {"code": 200, "msg": "success", "data": result}, status=status.HTTP_200_OK, ) class IrrigationMethodDetailView(APIView): """دریافت، ویرایش و حذف یک روش آبیاری.""" def _get_method(self, pk): return IrrigationMethod.objects.filter(pk=pk).first() @extend_schema( tags=["Irrigation"], summary="جزئیات روش آبیاری", description="مشخصات یک روش آبیاری را بر اساس شناسه برمی‌گرداند.", responses={ 200: build_response( IrrigationMethodDetailResponseSerializer, "جزئیات روش آبیاری.", ), 404: build_response( IrrigationValidationErrorSerializer, "روش آبیاری یافت نشد.", ), }, ) def get(self, request, pk): method = self._get_method(pk) if not method: return Response( {"code": 404, "msg": "روش آبیاری یافت نشد.", "data": None}, status=status.HTTP_404_NOT_FOUND, ) serializer = IrrigationMethodSerializer(method) return Response( {"code": 200, "msg": "success", "data": serializer.data}, status=status.HTTP_200_OK, ) @extend_schema( tags=["Irrigation"], summary="ویرایش کامل روش آبیاری", description="تمام فیلدهای یک روش آبیاری را آپدیت می‌کند.", request=IrrigationMethodSerializer, responses={ 200: build_response( IrrigationMethodDetailResponseSerializer, "روش آبیاری با موفقیت به‌روزرسانی شد.", ), 400: build_response( IrrigationValidationErrorSerializer, "داده ورودی نامعتبر است.", ), 404: build_response( IrrigationValidationErrorSerializer, "روش آبیاری یافت نشد.", ), }, ) def put(self, request, pk): method = self._get_method(pk) if not method: return Response( {"code": 404, "msg": "روش آبیاری یافت نشد.", "data": None}, status=status.HTTP_404_NOT_FOUND, ) serializer = IrrigationMethodSerializer(method, data=request.data) if not serializer.is_valid(): return Response( {"code": 400, "msg": "داده نامعتبر.", "data": serializer.errors}, status=status.HTTP_400_BAD_REQUEST, ) serializer.save() return Response( {"code": 200, "msg": "success", "data": serializer.data}, status=status.HTTP_200_OK, ) @extend_schema( tags=["Irrigation"], summary="ویرایش جزئی روش آبیاری", description="فقط فیلدهای ارسال‌شده آپدیت می‌شوند.", request=IrrigationMethodSerializer, responses={ 200: build_response( IrrigationMethodDetailResponseSerializer, "روش آبیاری با موفقیت به‌روزرسانی شد.", ), 400: build_response( IrrigationValidationErrorSerializer, "داده ورودی نامعتبر است.", ), 404: build_response( IrrigationValidationErrorSerializer, "روش آبیاری یافت نشد.", ), }, ) def patch(self, request, pk): method = self._get_method(pk) if not method: return Response( {"code": 404, "msg": "روش آبیاری یافت نشد.", "data": None}, status=status.HTTP_404_NOT_FOUND, ) serializer = IrrigationMethodSerializer(method, data=request.data, partial=True) if not serializer.is_valid(): return Response( {"code": 400, "msg": "داده نامعتبر.", "data": serializer.errors}, status=status.HTTP_400_BAD_REQUEST, ) serializer.save() return Response( {"code": 200, "msg": "success", "data": serializer.data}, status=status.HTTP_200_OK, ) @extend_schema( tags=["Irrigation"], summary="حذف روش آبیاری", description="یک روش آبیاری را حذف می‌کند.", responses={ 200: build_response( IrrigationValidationErrorSerializer, "روش آبیاری با موفقیت حذف شد.", ), 404: build_response( IrrigationValidationErrorSerializer, "روش آبیاری یافت نشد.", ), }, ) def delete(self, request, pk): method = self._get_method(pk) if not method: return Response( {"code": 404, "msg": "روش آبیاری یافت نشد.", "data": None}, status=status.HTTP_404_NOT_FOUND, ) method.delete() return Response( {"code": 200, "msg": "روش آبیاری با موفقیت حذف شد.", "data": None}, status=status.HTTP_200_OK, )