from django.utils.decorators import method_decorator
from django.views.decorators.cache import cache_control
from django.db.models import ProtectedError
from django.core.exceptions import ObjectDoesNotExist
from django.http import JsonResponse

from rest_framework.views import APIView
from rest_framework import permissions, status
from rest_framework.exceptions import ValidationError

from core.models import AppSettings
from core.utils import get_api_message
from .models import CustomerBuyer
from .serializers import BuyerWriteSerializer, BuyerReadSerializer


# --- Permissions ---
class HasCustomerProfile(permissions.BasePermission):
    def has_permission(self, request, view):
        return getattr(request.user, "customer", None) is not None


class IsBuyerOwner(permissions.BasePermission):
    def has_object_permission(self, request, view, obj: CustomerBuyer):
        customer = getattr(request.user, "customer", None)
        return customer is not None and obj.customer_id == customer.id

@method_decorator(cache_control(no_cache=True, must_revalidate=True, no_store=True), name="dispatch")
class BuyerListCreateAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]  # keep yours if you have custom perms
    
    def get(self, request):
        customer = getattr(request.user, "customer", None)
        if not customer:
            return JsonResponse(
                {
                    "success": True,
                    "message": get_api_message("BUYER_LIST", request),
                    "code": "BUYER_LIST",
                    "data": {"default_buyer": None, "buyers": []},
                },
                status=status.HTTP_200_OK,
            )

        default_buyer = None
        default_buyer_id = None
        try:
            app_settings = AppSettings.objects.get(customer_user=customer)
            default_buyer_id = (app_settings.default_buyer or {}).get("id")
        except AppSettings.DoesNotExist:
            pass

        buyers_qs = CustomerBuyer.objects.filter(customer=customer).order_by("-created_at")

        if default_buyer_id:
            try:
                default_buyer_obj = buyers_qs.get(pk=default_buyer_id)
                default_buyer = BuyerReadSerializer(
                    default_buyer_obj, context={"request": request}
                ).data
                buyers_qs = buyers_qs.exclude(pk=default_buyer_id)
            except CustomerBuyer.DoesNotExist:
                default_buyer = None

        buyers = BuyerReadSerializer(
            buyers_qs, many=True, context={"request": request}
        ).data

        return JsonResponse(
            {
                "success": True,
                "message": get_api_message("BUYER_LIST", request),
                "code": "BUYER_LIST",
                "data": {"default_buyer": default_buyer, "buyers": buyers},
            },
            status=status.HTTP_200_OK,
        )


    def post(self, request):
        serializer = BuyerWriteSerializer(data=request.data, context={"request": request})

        try:
            serializer.is_valid(raise_exception=True)

        except ValidationError as e:
            codes = e.get_codes() if hasattr(e, "get_codes") else {}

            def has_duplicate_code(obj):
                # Looks for duplicate-buyer-name anywhere in nested codes
                if isinstance(obj, str):
                    return obj == "duplicate-buyer-name"
                if isinstance(obj, list):
                    return any(has_duplicate_code(x) for x in obj)
                if isinstance(obj, dict):
                    return any(has_duplicate_code(v) for v in obj.values())
                return False

            if has_duplicate_code(codes):
                return JsonResponse(
                    {
                        "success": False,
                        "message": get_api_message("BUYER_DUPLICATE", request),
                        "code": "BUYER_DUPLICATE",
                        "errors": e.detail,
                    },
                    status=status.HTTP_409_CONFLICT,
                )

            return JsonResponse(
                {
                    "success": False,
                    "message": get_api_message("VALIDATION_ERROR", request),
                    "code": "VALIDATION_ERROR",
                    "errors": e.detail,
                },
                status=status.HTTP_400_BAD_REQUEST,
            )

        buyer = serializer.save()
        read_serializer = BuyerReadSerializer(buyer, context={"request": request})

        return JsonResponse(
            {
                "success": True,
                "message": get_api_message("BUYER_CREATED", request),
                "code": "BUYER_CREATED",
                "data": read_serializer.data,
            },
            status=status.HTTP_201_CREATED,
        )


# --- Detail / Update / Delete ---
@method_decorator(cache_control(no_cache=True, must_revalidate=True, no_store=True), name="dispatch")
class BuyerDetailAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated, HasCustomerProfile]

    def get_object(self, id, request):
        customer = getattr(request.user, "customer", None)
        try:
            obj = CustomerBuyer.objects.get(id=id, customer=customer)
            if not IsBuyerOwner().has_object_permission(request, self, obj):
                return None
            return obj
        except CustomerBuyer.DoesNotExist:
            return None

    def get(self, request, id):
        obj = self.get_object(id, request)
        if not obj:
            return JsonResponse(
                {
                    "success": False,
                    "message": get_api_message("BUYER_NOT_FOUND", request),
                    "code": "BUYER_NOT_FOUND",
                },
                status=status.HTTP_404_NOT_FOUND,
            )

        serializer = BuyerReadSerializer(obj)
        return JsonResponse(
            {
                "success": True,
                "message": get_api_message("BUYER_FETCHED", request),
                "code": "BUYER_FETCHED",
                "data": serializer.data,
            },
            status=status.HTTP_200_OK,
        )

    def put(self, request, id):
        obj = self.get_object(id, request)
        if not obj:
            return JsonResponse(
                {
                    "success": False,
                    "message": get_api_message("BUYER_NOT_FOUND", request),
                    "code": "BUYER_NOT_FOUND",
                },
                status=404,
            )

        serializer = BuyerWriteSerializer(
            obj, data=request.data, context={"request": request}
        )
        try:
            serializer.is_valid(raise_exception=True)
        except ValidationError as e:
            return JsonResponse(
                {
                    "success": False,
                    "message": get_api_message("VALIDATION_ERROR", request),
                    "code": "VALIDATION_ERROR",
                    "errors": e.detail,
                },
                status=status.HTTP_400_BAD_REQUEST,
            )

        updated = serializer.save()
        read_serializer = BuyerReadSerializer(updated)
        return JsonResponse(
            {
                "success": True,
                "message": get_api_message("BUYER_UPDATED", request),
                "code": "BUYER_UPDATED",
                "data": read_serializer.data,
            },
            status=status.HTTP_200_OK,
        )

    def patch(self, request, id):
        obj = self.get_object(id, request)
        if not obj:
            return JsonResponse(
                {
                    "success": False,
                    "message": get_api_message("BUYER_NOT_FOUND", request),
                    "code": "BUYER_NOT_FOUND",
                },
                status=404,
            )

        serializer = BuyerWriteSerializer(
            obj, data=request.data, partial=True, context={"request": request}
        )
        try:
            serializer.is_valid(raise_exception=True)
        except ValidationError as e:
            return JsonResponse(
                {
                    "success": False,
                    "message": get_api_message("VALIDATION_ERROR", request),
                    "code": "VALIDATION_ERROR",
                    "errors": e.detail,
                },
                status=status.HTTP_400_BAD_REQUEST,
            )

        updated = serializer.save()
        read_serializer = BuyerReadSerializer(updated)
        return JsonResponse(
            {
                "success": True,
                "message": get_api_message("BUYER_UPDATED", request),
                "code": "BUYER_UPDATED",
                "data": read_serializer.data,
            },
            status=status.HTTP_200_OK,
        )

    def delete(self, request, id):
        obj = self.get_object(id, request)
        if not obj:
            return JsonResponse(
                {
                    "success": False,
                    "message": get_api_message("BUYER_NOT_FOUND", request),
                    "code": "BUYER_NOT_FOUND",
                },
                status=404,
            )

        # 1️⃣ Block default buyer
        is_default = AppSettings.objects.filter(
            customer_user=obj.customer,
            default_buyer__id=obj.id,
        ).exists()
        if is_default:
            return JsonResponse(
                {
                    "success": False,
                    "message": get_api_message("BUYER_DEFAULT_DELETE_BLOCKED", request),
                    "code": "BUYER_DEFAULT_DELETE_BLOCKED",
                },
                status=status.HTTP_409_CONFLICT,
            )

        # 2️⃣ Block related records
        related_fields = [
            f for f in obj._meta.get_fields()
            if (f.one_to_many or f.one_to_one) and f.auto_created
        ]
        for rel in related_fields:
            accessor = rel.get_accessor_name()
            related_attr = getattr(obj, accessor)
            try:
                if hasattr(related_attr, "exists") and related_attr.exists():
                    return JsonResponse(
                        {
                            "success": False,
                            "message": get_api_message("BUYER_HAS_RELATED_RECORDS", request),
                            "code": "BUYER_HAS_RELATED_RECORDS",
                        },
                        status=status.HTTP_409_CONFLICT,
                    )
            except ObjectDoesNotExist:
                pass

        # 3️⃣ Safe delete
        try:
            obj.delete()
            return JsonResponse(
                {
                    "success": True,
                    "message": get_api_message("BUYER_DELETED", request),
                    "code": "BUYER_DELETED",
                },
                status=200,
            )
        except ProtectedError:
            return JsonResponse(
                {
                    "success": False,
                    "message": get_api_message("BUYER_HAS_RELATED_RECORDS", request),
                    "code": "BUYER_HAS_RELATED_RECORDS",
                },
                status=status.HTTP_409_CONFLICT,
            )
