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 rag.failure_contract import RAGServiceError

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 RAGServiceError as exc:
            return Response(
                {"code": exc.http_status, "msg": exc.contract.message, "data": exc.to_dict()},
                status=exc.http_status,
            )
        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,
        )
