from datetime import datetime, timedelta
from django.core.exceptions import ValidationError as DjangoValidationError
from django.utils import timezone
from django.utils.dateparse import parse_date
from rest_framework.permissions import IsAuthenticated
from account.permissions import (
    HasTabPermission,
    user_can_see_all_shop_data,
    get_user_data_filter,
)
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.filters import SearchFilter
from rest_framework import status, viewsets
from rest_framework.decorators import action
from rest_framework.exceptions import ValidationError
from rest_framework.response import Response
from shop_management.models.data.customer_balance_payment import CustomerBalancePayment
from shop_management.models.data.customer import Customer
from shop_management.models.data.account_transaction import AccountTransaction
from shop_management.serializers.data.customer_balance_payment import CustomerBalancePaymentSerializer
from shop_management.views.data.pagination import CustomPagination


class CustomerBalancePaymentViewSet(viewsets.ModelViewSet):
    serializer_class = CustomerBalancePaymentSerializer
    permission_classes = [IsAuthenticated, HasTabPermission]
    required_tabs = ["customers", "sales_payments"]
    filter_backends = [DjangoFilterBackend, SearchFilter]
    filterset_fields = ["customer", "customer__shop", "currency", "is_void"]
    pagination_class = CustomPagination

    def get_queryset(self):
        can_see_all = any(
            user_can_see_all_shop_data(self.request.user, t)
            for t in self.required_tabs
        )
        if can_see_all:
            queryset = CustomerBalancePayment.objects.all().select_related(
                "customer",
                "customer__shop",
                "currency",
                "account",
                "account__currency",
                "supplier_branch",
                "customer_branch",
            )
        else:
            queryset = (
                CustomerBalancePayment.objects.filter(
                    get_user_data_filter(self.request.user, "customer__shop")
                )
                .select_related(
                    "customer",
                    "customer__shop",
                    "currency",
                    "account",
                    "account__currency",
                    "supplier_branch",
                    "customer_branch",
                )
            )
        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:
                start_dt = timezone.make_aware(
                    datetime.combine(start_date, datetime.min.time()),
                    timezone.get_current_timezone(),
                )
                queryset = queryset.filter(payment_date__gte=start_dt)
        if end_date:
            end_date = parse_date(end_date)
            if end_date:
                end_dt = timezone.make_aware(
                    datetime.combine(end_date + timedelta(days=1), datetime.min.time()),
                    timezone.get_current_timezone(),
                )
                queryset = queryset.filter(payment_date__lt=end_dt)
        shop = self.request.query_params.get("shop")
        if shop:
            queryset = queryset.filter(customer__shop_id=shop)
        return queryset.order_by("-payment_date")

    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()
        try:
            instance.void(user=request.user, reason="Cancelled via balance payment deletion")
        except DjangoValidationError as exc:
            msg = exc.message_dict if hasattr(exc, "message_dict") else exc.messages
            raise ValidationError(msg)
        return Response(status=status.HTTP_204_NO_CONTENT)

    def perform_destroy(self, instance):
        instance.void(user=self.request.user, reason="Cancelled via balance payment deletion")

    @action(detail=True, methods=["post"])
    def void(self, request, pk=None):
        instance = self.get_object()
        reason = request.data.get("reason", "Cancelled by user")
        try:
            instance.void(user=request.user, reason=reason)
        except DjangoValidationError as exc:
            msg = exc.message_dict if hasattr(exc, "message_dict") else exc.messages
            raise ValidationError(msg)
        return Response(self.get_serializer(instance).data, status=status.HTTP_200_OK)

    def _resolve_virtual_general_customer(self, data):
        customer_value = str(data.get("customer") or "")
        # format: general-customer::<shop_id>::<name>::<phone>
        if not customer_value.startswith("general-customer::"):
            return data
        parts = customer_value.split("::", 3)
        if len(parts) < 4:
            return data
        _, shop_id, name, phone = parts
        name = (name or "").strip()
        phone = (phone or "").strip()
        if not shop_id or not name:
            return data
        customer_obj, _ = Customer.objects.get_or_create(
            shop_id=shop_id,
            name=name,
            defaults={"contact": phone or None, "is_general_customer": True, "created_by": self.request.user},
        )
        if phone and customer_obj.contact != phone:
            customer_obj.contact = phone
            customer_obj.save(update_fields=["contact"])
        mutable = data.copy()
        mutable["customer"] = str(customer_obj.id)
        return mutable

    def create(self, request, *args, **kwargs):
        request._full_data = self._resolve_virtual_general_customer(request.data)
        return super().create(request, *args, **kwargs)

    def update(self, request, *args, **kwargs):
        request._full_data = self._resolve_virtual_general_customer(request.data)
        return super().update(request, *args, **kwargs)
