# shop_management/views/data/expense.py
from rest_framework.permissions import IsAuthenticated
from rest_framework import status
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.exceptions import ValidationError
from django.core.exceptions import ValidationError as DjangoValidationError
from account.permissions import (
    HasActionPermission,
    HasTabPermission,
    user_can_see_all_shop_data,
    get_user_data_filter,
    get_user_shop_filter,
)
from shop_management.views.data.base import DataRootViewSet
from shop_management.models.data.expense import Expense, ExpenseCategory
from shop_management.models.data.shop import Shop
from shop_management.serializers.data.expense import ExpenseSerializer, ExpenseCategorySerializer
from shop_management.views.data.pagination import CustomPagination
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.filters import SearchFilter
from django.utils.dateparse import parse_date
from django.db.models import Q
from shop_management.models.data.account_transaction import AccountTransaction
from shop_management.services.expenses import post_expense, void_expense


class ExpenseCategoryViewSet(DataRootViewSet):
    serializer_class = ExpenseCategorySerializer
    permission_classes = [IsAuthenticated, HasTabPermission]
    required_tab = "expense_categories"
    pagination_class = CustomPagination
    filter_backends = [SearchFilter]
    search_fields = ["name", "description"]

    def get_queryset(self):
        if user_can_see_all_shop_data(self.request.user, self.required_tab):
            return ExpenseCategory.objects.all().order_by("-id")
        return ExpenseCategory.objects.filter(get_user_data_filter(self.request.user, "shop")).distinct().order_by("-id")


class ExpenseViewSet(DataRootViewSet):
    serializer_class = ExpenseSerializer
    permission_classes = [IsAuthenticated, HasTabPermission, HasActionPermission]
    action_permission_map = {
        "create": "expenses.create_expense",
        "post": "expenses.post_expense",
        "void": "expenses.void_expense",
    }
    required_tab = "expenses"
    pagination_class = CustomPagination
    filter_backends = [DjangoFilterBackend, SearchFilter]
    filterset_fields = ["currency", "expense_by", "category", "status"]
    search_fields = ["expense_number", "expense_by", "notes"]

    def get_queryset(self):
        requested_shop = self.request.query_params.get("shop")

        if user_can_see_all_shop_data(self.request.user, self.required_tab):
            queryset = Expense.objects.all()
        else:
            branch_filter = get_user_data_filter(self.request.user, "shop")
            allowed_shops = Shop.objects.filter(get_user_shop_filter(self.request.user))
            queryset = Expense.objects.filter(
                branch_filter | (Q(shop__isnull=True) & Q(currency__shop__in=allowed_shops))
            ).distinct()

        if requested_shop:
            queryset = queryset.filter(
                Q(shop=requested_shop) | (Q(shop__isnull=True) & Q(currency__shop=requested_shop))
            )

        # Filter by payment_date range
        start_date = self.request.query_params.get("start_date")
        end_date = self.request.query_params.get("end_date")

        if start_date:
            start_date = parse_date(start_date)
            if start_date:
                queryset = queryset.filter(payment_date__date__gte=start_date)

        if end_date:
            end_date = parse_date(end_date)
            if end_date:
                queryset = queryset.filter(payment_date__date__lte=end_date)

        return queryset.order_by("-id")

    def destroy(self, request, *args, **kwargs):
        if self.get_object().status != Expense.Status.DRAFT:
            return Response({"detail": "Only draft expenses can be deleted."}, status=status.HTTP_400_BAD_REQUEST)
        return super().destroy(request, *args, **kwargs)

    def _run(self, request, operation):
        expense = self.get_object()
        try:
            result = operation(expense.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 expense_id: post_expense(expense_id, user=request.user))

    @action(detail=True, methods=["post"])
    def void(self, request, pk=None):
        return self._run(request, lambda expense_id: void_expense(expense_id, user=request.user, reason=request.data.get("reason", "")))
