from django.apps import apps 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 .serializers import ( SoilAnomalyDetectionRequestSerializer, SoilAnomalyDetectionResponseSerializer, SoilHealthSummaryRequestSerializer, SoilHealthSummaryResponseSerializer, SoilMoistureHeatmapRequestSerializer, SoilMoistureHeatmapResponseSerializer, ) SoileHeatmapEnvelopeSerializer = build_envelope_serializer( "SoileHeatmapEnvelopeSerializer", SoilMoistureHeatmapResponseSerializer, ) SoileErrorSerializer = build_envelope_serializer( "SoileErrorSerializer", data_required=False, allow_null=True, ) SoileAnomalyEnvelopeSerializer = build_envelope_serializer( "SoileAnomalyEnvelopeSerializer", SoilAnomalyDetectionResponseSerializer, ) SoileHealthEnvelopeSerializer = build_envelope_serializer( "SoileHealthEnvelopeSerializer", SoilHealthSummaryResponseSerializer, ) class SoilMoistureHeatmapView(APIView): @extend_schema( tags=["Soile"], summary="دریافت heatmap رطوبت خاک مزرعه", description=( "با دریافت farm_uuid، heatmap رطوبت خاک را با وزن دهی زمانی/فضایی، " "mask مرز مزرعه و برآورد عدم قطعیت از app مستقل soile برمی گرداند." ), request=SoilMoistureHeatmapRequestSerializer, responses={ 200: build_response( SoileHeatmapEnvelopeSerializer, "داده heatmap رطوبت خاک مزرعه با موفقیت بازگردانده شد.", ), 400: build_response( SoileErrorSerializer, "داده ورودی نامعتبر است.", ), 404: build_response( SoileErrorSerializer, "مزرعه یافت نشد.", ), }, examples=[ OpenApiExample( "نمونه درخواست soile", value={"farm_uuid": "11111111-1111-1111-1111-111111111111"}, request_only=True, ) ], ) def post(self, request): serializer = SoilMoistureHeatmapRequestSerializer(data=request.data) if not serializer.is_valid(): return Response( {"code": 400, "msg": "داده نامعتبر.", "data": serializer.errors}, status=status.HTTP_400_BAD_REQUEST, ) service = apps.get_app_config("soile").get_soil_moisture_service() try: data = service.get_heatmap(farm_uuid=str(serializer.validated_data["farm_uuid"])) except ValueError as exc: return Response( {"code": 404, "msg": str(exc), "data": None}, status=status.HTTP_404_NOT_FOUND, ) return Response( {"code": 200, "msg": "success", "data": data}, status=status.HTTP_200_OK, ) class SoilHealthSummaryView(APIView): @extend_schema( tags=["Soile"], summary="خلاصه سلامت و رطوبت خاک مزرعه", description="با دریافت farm_uuid، امتیاز سلامت خاک/سنسور و میانگین رطوبت فعلی خاک را برمی گرداند.", request=SoilHealthSummaryRequestSerializer, responses={ 200: build_response(SoileHealthEnvelopeSerializer, "خلاصه سلامت خاک با موفقیت بازگردانده شد."), 400: build_response(SoileErrorSerializer, "داده ورودی نامعتبر است."), 404: build_response(SoileErrorSerializer, "مزرعه یافت نشد."), }, examples=[ OpenApiExample( "نمونه درخواست soil health", value={"farm_uuid": "11111111-1111-1111-1111-111111111111"}, request_only=True, ) ], ) def post(self, request): serializer = SoilHealthSummaryRequestSerializer(data=request.data) if not serializer.is_valid(): return Response( {"code": 400, "msg": "داده نامعتبر.", "data": serializer.errors}, status=status.HTTP_400_BAD_REQUEST, ) service = apps.get_app_config("soile").get_soil_health_service() try: data = service.get_health_summary(farm_uuid=str(serializer.validated_data["farm_uuid"])) except ValueError as exc: return Response( {"code": 404, "msg": str(exc), "data": None}, status=status.HTTP_404_NOT_FOUND, ) return Response({"code": 200, "msg": "success", "data": data}, status=status.HTTP_200_OK) class SoilAnomalyDetectionView(APIView): @extend_schema( tags=["Soile"], summary="تحلیل ناهنجاری خاک با کمک RAG", description="با دریافت farm_uuid، ناهنجاری های آماری داده های خاک را استخراج می کند و تفسیر تخصصی آن را با پایگاه دانش و tone مستقل برمی گرداند.", request=SoilAnomalyDetectionRequestSerializer, responses={ 200: build_response( SoileAnomalyEnvelopeSerializer, "خروجی تحلیل ناهنجاری خاک با موفقیت بازگردانده شد.", ), 400: build_response( SoileErrorSerializer, "داده ورودی نامعتبر است.", ), 404: build_response( SoileErrorSerializer, "مزرعه یافت نشد.", ), 500: build_response( SoileErrorSerializer, "خطا در تحلیل ناهنجاری خاک.", ), }, examples=[ OpenApiExample( "نمونه درخواست anomaly", value={"farm_uuid": "11111111-1111-1111-1111-111111111111"}, request_only=True, ) ], ) def post(self, request): serializer = SoilAnomalyDetectionRequestSerializer(data=request.data) if not serializer.is_valid(): return Response( {"code": 400, "msg": "داده نامعتبر.", "data": serializer.errors}, status=status.HTTP_400_BAD_REQUEST, ) service = apps.get_app_config("soile").get_soil_anomaly_service() try: data = service.get_anomaly_detection( farm_uuid=str(serializer.validated_data["farm_uuid"]) ) except ValueError as exc: return Response( {"code": 404, "msg": str(exc), "data": None}, status=status.HTTP_404_NOT_FOUND, ) 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": data}, status=status.HTTP_200_OK, )