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 HasActionPermission, HasTabPermission, get_user_data_filter
from shop_management.models.data.opening_balance import FinancialOpeningBalance
from shop_management.serializers.data.opening_balance import FinancialOpeningBalanceSerializer
from shop_management.services.opening_balances import post_financial_opening, void_financial_opening
from shop_management.views.data.pagination import CustomPagination


class FinancialOpeningBalanceViewSet(viewsets.ModelViewSet):
    serializer_class = FinancialOpeningBalanceSerializer
    permission_classes = [IsAuthenticated, HasTabPermission, HasActionPermission]
    required_tab = "accounts"
    action_permission_map = {"create": "accounting.create_manual_journal", "post": "accounting.post_journal", "void": "accounting.void_journal"}
    pagination_class = CustomPagination
    filterset_fields = ["shop", "balance_type", "status", "currency"]

    def get_queryset(self):
        return FinancialOpeningBalance.objects.filter(
            get_user_data_filter(self.request.user, "shop")
        ).select_related("shop", "currency", "customer", "supplier", "financial_account", "journal_entry")

    def perform_destroy(self, instance):
        if instance.status != instance.Status.DRAFT:
            raise ValidationError("Only draft opening balances can be deleted.")
        instance.delete()

    def _run(self, service, **kwargs):
        try:
            document = service(self.get_object().pk, user=self.request.user, **kwargs)
        except DjangoValidationError as exc:
            raise ValidationError(exc.message_dict if hasattr(exc, "message_dict") else exc.messages)
        return Response(self.get_serializer(document).data, status=status.HTTP_200_OK)

    @action(detail=True, methods=["post"])
    def post(self, request, pk=None):
        return self._run(post_financial_opening)

    @action(detail=True, methods=["post"])
    def void(self, request, pk=None):
        return self._run(void_financial_opening, reason=request.data.get("reason", ""))
