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 .models import IrrigationMethod
from .serializers import (
    IrrigationMethodSerializer,
    IrrigationPlanParserRequestSerializer,
    IrrigationPlanParserResponseSerializer,
    IrrigationRecommendRequestSerializer,
    WaterStressRequestSerializer,
    WaterStressResponseSerializer,
)


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,
)
IrrigationPlanParserEnvelopeSerializer = build_envelope_serializer(
    "IrrigationPlanParserEnvelopeSerializer",
    IrrigationPlanParserResponseSerializer,
)
WaterStressEnvelopeSerializer = build_envelope_serializer(
    "WaterStressEnvelopeSerializer",
    WaterStressResponseSerializer,
)

IRRIGATION_RECOMMENDATION_INTERNAL_KEYS = {
    "raw_response",
    "simulation_optimizer",
    "selected_irrigation_method",
}


def _prepare_irrigation_recommendation_response(value):
    if isinstance(value, dict):
        cleaned = {}
        for key, item in value.items():
            if key in IRRIGATION_RECOMMENDATION_INTERNAL_KEYS or item is None:
                continue
            normalized = _prepare_irrigation_recommendation_response(item)
            if normalized is not None:
                cleaned[key] = normalized
        return cleaned

    if isinstance(value, list):
        cleaned_items = []
        for item in value:
            normalized = _prepare_irrigation_recommendation_response(item)
            if normalized is not None:
                cleaned_items.append(normalized)
        return cleaned_items

    return value


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 با farm_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={
                    "farm_uuid": "11111111-1111-1111-1111-111111111111",
                    "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
        farm_uuid = validated["farm_uuid"]
        plant_name = validated.get("plant_name")
        growth_stage = validated.get("growth_stage")
        irrigation_method_name = validated.get("irrigation_method_name")
        try:
            result = get_irrigation_recommendation(
                farm_uuid=farm_uuid,
                plant_name=plant_name,
                growth_stage=growth_stage,
                irrigation_method_name=irrigation_method_name,
            )
        except Exception as exc:
            return Response(
                {"code": 500, "msg": f"خطا در تولید توصیه آبیاری: {exc}", "data": None},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )

        final_result = _prepare_irrigation_recommendation_response(result) or {}
        return Response(
            {"code": 200, "msg": "success", "data": final_result},
            status=status.HTTP_200_OK,
        )


class IrrigationPlanParserView(APIView):
    @extend_schema(
        tags=["Irrigation Recommendation"],
        summary="استخراج برنامه آبیاری از متن آزاد",
        description=(
            "توضیح متنی کاربر درباره برنامه آبیاری را می گیرد و آن را به JSON ساختاریافته تبدیل می کند. "
            "اگر اطلاعات کافی نباشد، سوالات تکمیلی لازم را برمی گرداند تا در درخواست بعدی پاسخ داده شوند."
        ),
        request=IrrigationPlanParserRequestSerializer,
        responses={
            200: build_response(
                IrrigationPlanParserEnvelopeSerializer,
                "نتیجه استخراج یا سوالات تکمیلی برنامه آبیاری.",
            ),
            400: build_response(
                IrrigationValidationErrorSerializer,
                "داده ورودی نامعتبر است.",
            ),
            500: build_response(
                IrrigationValidationErrorSerializer,
                "خطا در پردازش برنامه آبیاری.",
            ),
        },
        examples=[
            OpenApiExample(
                "نمونه درخواست کامل",
                value={
                    "message": "برای گوجه فرنگی با آبیاری قطره ای هر سه روز یک بار صبح زود 25 دقیقه آبیاری می کنم و حدود 18 لیتر برای هر بوته می دهم.",
                    "farm_uuid": "11111111-1111-1111-1111-111111111111",
                },
                request_only=True,
            ),
            OpenApiExample(
                "نمونه درخواست تکمیلی",
                value={
                    "partial_plan": {
                        "crop_name": "گوجه فرنگی",
                        "irrigation_method": "قطره ای",
                    },
                    "answers": {
                        "water_amount_per_event": "18 لیتر برای هر بوته",
                        "preferred_time_of_day": "صبح زود",
                    },
                },
                request_only=True,
            ),
        ],
    )
    def post(self, request):
        serializer = IrrigationPlanParserRequestSerializer(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
        service = apps.get_app_config("irrigation").get_free_text_plan_parser_service()
        try:
            result = service.parse_plan(
                message=validated.get("message", ""),
                answers=validated.get("answers"),
                partial_plan=validated.get("partial_plan"),
                farm_uuid=validated.get("farm_uuid"),
            )
        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": "موفق", "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,
        )


class WaterStressView(APIView):
    @extend_schema(
        tags=["Irrigation"],
        summary="شاخص تنش آبی مزرعه",
        description=(
            "با دریافت farm_uuid، شاخص تنش آبی مزرعه را با استفاده از شبیه سازی "
            "crop_simulation و داده هایی مثل رطوبت خاک، ET0، بارش، مرحله رشد و پارامترهای خاک برمی گرداند."
        ),
        request=WaterStressRequestSerializer,
        responses={
            200: build_response(WaterStressEnvelopeSerializer, "شاخص تنش آبی مزرعه."),
            400: build_response(IrrigationValidationErrorSerializer, "پارامتر ورودی نامعتبر است."),
            404: build_response(IrrigationValidationErrorSerializer, "مزرعه یافت نشد."),
        },
        examples=[
            OpenApiExample(
                "نمونه درخواست water stress",
                value={
                    "farm_uuid": "11111111-1111-1111-1111-111111111111",
                    "irrigation_recommendation": {"events": [{"date": "2026-04-25", "amount": 2.5}]},
                    "fertilization_recommendation": {
                        "events": [{"date": "2026-04-20", "N_amount": 45, "N_recovery": 0.7}]
                    },
                },
                request_only=True,
            )
        ],
    )
    def post(self, request):
        serializer = WaterStressRequestSerializer(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("irrigation").get_water_stress_service()
        try:
            data = service.get_water_stress(
                farm_uuid=serializer.validated_data["farm_uuid"],
                plant_name=serializer.validated_data.get("plant_name"),
                irrigation_recommendation=serializer.validated_data.get("irrigation_recommendation"),
                fertilization_recommendation=serializer.validated_data.get("fertilization_recommendation"),
            )
        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)

    @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,
        )
