from django.core.exceptions import ValidationError as DjangoValidationError
from rest_framework import status, viewsets
from rest_framework.decorators import action
from rest_framework.exceptions import ValidationError
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response

from account.permissions import HasTabPermission, HasActionPermission, get_user_data_filter, user_can_see_all_shop_data
from shop_management.models.data.supplier_payment import SupplierPayment
from shop_management.serializers.data.supplier_payment import SupplierPaymentSerializer
from shop_management.services.supplier_payments import post_supplier_payment, void_supplier_payment
from shop_management.views.data.pagination import CustomPagination


class SupplierPaymentViewSet(viewsets.ModelViewSet):
    serializer_class = SupplierPaymentSerializer
    permission_classes = [IsAuthenticated, HasTabPermission, HasActionPermission]
    action_permission_map = {"create": "finance.make_supplier_payment", "post": "finance.make_supplier_payment", "void": "finance.make_supplier_payment"}
    required_tab = "purchase_payments"
    pagination_class = CustomPagination
    filterset_fields = ["shop", "supplier", "currency", "status"]

    def get_queryset(self):
        queryset = SupplierPayment.objects.select_related("supplier", "shop", "financial_account", "currency").prefetch_related("allocations__purchase")
        if not user_can_see_all_shop_data(self.request.user, self.required_tab):
            queryset = queryset.filter(get_user_data_filter(self.request.user, "shop"))
        return queryset.order_by("-payment_date", "-id")

    def destroy(self, request, *args, **kwargs):
        payment = self.get_object()
        if payment.status != SupplierPayment.Status.DRAFT:
            return Response({"detail": "Only draft payments can be deleted."}, status=status.HTTP_400_BAD_REQUEST)
        return super().destroy(request, *args, **kwargs)

    def _run(self, request, operation):
        payment = self.get_object()
        try:
            result = operation(payment.pk)
        except DjangoValidationError as exc:
            raise ValidationError(exc.message_dict if hasattr(exc, "message_dict") else exc.messages)
        return Response(self.get_serializer(result).data)

    @action(detail=True, methods=["post"])
    def post(self, request, pk=None):
        return self._run(request, lambda payment_id: post_supplier_payment(payment_id, user=request.user))

    @action(detail=True, methods=["post"])
    def void(self, request, pk=None):
        return self._run(request, lambda payment_id: void_supplier_payment(payment_id, user=request.user, reason=request.data.get("reason", "")))
