from django.db import transaction
from order.models import Cart
from django.utils.translation import override
from .permissons import PaymentCallBackPermissions
from azbankgateways.models.enum import PaymentStatus
from azbankgateways.models import Bank
from rest_framework import serializers
from rest_framework.response import Response
from django.utils import timezone
from django.shortcuts import render
from rest_framework.views import APIView, Response
from django.shortcuts import get_object_or_404
from product.models import ProductVariant
from rest_framework.permissions import IsAuthenticated
from .serializers import *
# from cart.models import
from rest_framework import status
from .models import OrderItemModel, OrderModel, DiscountCode
from .permissons import CanDeleteCartItemPermissions, GetOrderPermission, SetAddressPermissions
from azbankgateways import bankfactories, models as bank_models
from azbankgateways.exceptions import AZBankGatewaysException
from drf_spectacular.utils import extend_schema, OpenApiParameter, OpenApiTypes, extend_schema_view
from utils.pagination import StructurePagination
from order.models import OrderModel
from django.urls import reverse
from account.models import UserAddressModel


# try:
#     pass
# except DiscountNotAvailableError:
#     pass


@extend_schema_view(
    post=extend_schema(tags=["cart discount code"]),
    delete=extend_schema(tags=["cart discount code"]),
)
class ApplyDiscountView(APIView):
    serializer_class = DiscountCodeSerializer
    permission_classes = [IsAuthenticated]

    def post(self, request):
        cart_order, created = Cart.objects.get_or_create(
            user=request.user,
        )
        discount_code = get_object_or_404(
            DiscountCode, code=request.data.get('code'))

        if not discount_code.is_valid():
            return Response({'detail': discount_code.not_valid_reason()}, status=status.HTTP_400_BAD_REQUEST)
        cart_order.discount_code = discount_code
        cart_order.save()
        return Response({'detail': 'کد تخفیف با موفقیت اعمال شد'}, status=status.HTTP_200_OK)

    def delete(self, request):
        cart_order, created = Cart.objects.get_or_create(
            user=request.user,
        )
        cart_order.discount_code = None
        cart_order.save()
        return Response({'detail': 'کد تخفیف با موفقیت حذف شد'}, status=status.HTTP_204_NO_CONTENT)


@extend_schema_view(
    post=extend_schema(tags=["cart special discount code"]),
    delete=extend_schema(tags=["cart special discount code"]),
)
class ApplySpecialDiscountView(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request):
        from account.models import SpecialDiscountCode

        cart, created = Cart.objects.get_or_create(user=request.user)
        code = request.data.get('code')

        if not code:
            return Response({'detail': 'کد تخفیف ویژه را وارد کنید'}, status=status.HTTP_400_BAD_REQUEST)

        try:
            special_discount_code = SpecialDiscountCode.objects.get(code=code)
        except SpecialDiscountCode.DoesNotExist:
            return Response({'detail': 'کد تخفیف ویژه معتبر نیست'}, status=status.HTTP_404_NOT_FOUND)

        # Apply the special discount code to cart
        cart.special_discount_code = special_discount_code
        cart.save()

        return Response({'detail': 'کد تخفیف ویژه با موفقیت اعمال شد'}, status=status.HTTP_200_OK)

    def delete(self, request):
        cart, created = Cart.objects.get_or_create(user=request.user)
        cart.special_discount_code = None
        cart.save()
        return Response({'detail': 'کد تخفیف ویژه با موفقیت حذف شد'}, status=status.HTTP_204_NO_CONTENT)


class CartItemClear(APIView):
    permission_classes = [IsAuthenticated]
    serializer_class = OrderItemSerailzier

    @extend_schema(
        tags=["order cart"]
    )
    def delete(self, request):
        cart_order, created = Cart.objects.get_or_create(
            user=request.user,
        )
        cart_order.items.all().delete()
        return Response({'detail': f'سبد خرید با موفقیت خالی شد'}, status=status.HTTP_204_NO_CONTENT)


@extend_schema_view(
    post=extend_schema(tags=["order cart"]),
    delete=extend_schema(tags=["order cart"]),
)
class CartItemViews(APIView):
    permission_classes = [IsAuthenticated]
    serializer_class = OrderItemSerailzier

    def post(self, request, pk):
        product_variant = get_object_or_404(ProductVariant, pk=pk)
        response = 'محصول با موفقیت به سبد خرید اضافه شد'
        quantity = request.data.get('quantity', 1)
        quantity = max(quantity, 0)
        if product_variant.in_stock < quantity:
            quantity = product_variant.in_stock
            response = 'تعداد درخواستی بیشتر از موجودی محصول میباشد'

        cart_order, created = Cart.objects.get_or_create(user=request.user)
        order_item, created = CartItem.objects.get_or_create(
            cart=cart_order, product_variant=product_variant, defaults={'quantity': quantity})
        if not created and order_item.quantity:
            order_item.quantity = quantity
            order_item.save()
        if not order_item.quantity:
            order_item.delete()
        return Response({'detail': response, 'count': quantity}, status=status.HTTP_202_ACCEPTED)

    def delete(self, request, pk):
        cart_item = get_object_or_404(CartItem, pk=pk)
        permission = CanDeleteCartItemPermissions()

        if not permission.has_object_permission(request, self, cart_item):
            return Response({"detail": permission.message}, status=status.HTTP_403_FORBIDDEN)

        cart_item.delete()
        return Response(
            {"detail": "محصول با موفقیت از سبد خرید شما حذف شد"},
            status=status.HTTP_204_NO_CONTENT,
        )


class CartView(APIView):
    permission_classes = [IsAuthenticated]
    serializer_class = CartSerializer

    @extend_schema(
        tags=["order cart"]
    )
    def get(self, request):
        user = request.user
        cart_instance, created = Cart.objects.get_or_create(user=user)
        cart_ser = self.serializer_class(
            instance=cart_instance, context={'request': request})
        return Response(cart_ser.data, status=status.HTTP_200_OK)


class OrderlistView(APIView):
    permission_classes = [IsAuthenticated]
    serializer_class = OrderListSerializer
    pagination_class = StructurePagination

    @extend_schema(
        parameters=[
            OpenApiParameter(
                name="limit",
                description="لیمیتش",
                required=False,
                type=OpenApiTypes.INT,
            ),
            OpenApiParameter(
                name="offset",
                description="افستش",
                required=False,
                type=OpenApiTypes.INT,
            ),
            OpenApiParameter(
                name="status",
                description=(
                    "['ADMIN_PENDING', 'PENDING', 'POSTED', 'RECEIVED', 'CANCELED', 'REFUNDED']"
                ),
                required=False,
                type=OpenApiTypes.STR,
            ),
            OpenApiParameter(
                name="sort",
                description=(
                    "Sort results by one of the following fields:\n"
                    "['created_at', '-created_at', 'final_price', '-final_price']"
                    "\nPrefix with `-` for descending order."
                ),
                required=False,
                type=OpenApiTypes.STR,
            ),
        ],
        tags=["order"]
    )
    def get(self, request):
        user = request.user
        orders = OrderModel.objects.filter(user=user).exclude(status="CART")
        status_filter = request.query_params.get("status", None)
        sort = request.query_params.get('sort', None)
        if status_filter in ['ADMIN_PENDING', 'PENDING', 'POSTED', 'RECEIVED', 'CANCELED', 'REFUNDED']:
            orders.filter(status=status_filter)
        if sort:
            if sort not in ['created_at', '-created_at', 'final_price', '-final_price']:
                return Response({'detail': 'پارامتر sort اشتباه است'}, status=status.HTTP_400_BAD_REQUEST)
            orders = orders.order_by(sort)
        paginator = self.pagination_class()
        paginated_orders = paginator.paginate_queryset(orders, request)
        orders_ser = self.serializer_class(
            instance=paginated_orders, many=True, context={'request': request})
        return paginator.get_paginated_response(orders_ser.data)


class OrderGetView(APIView):
    permission_classes = [IsAuthenticated, GetOrderPermission]
    serializer_class = OrderGetSerializer

    def get(self, request, pk):
        order_object = get_object_or_404(OrderModel, pk=pk)

        permission = GetOrderPermission()
        if not permission.has_object_permission(request, self, order_object):
            return Response({"detail": permission.message}, status=status.HTTP_403_FORBIDDEN)

        order_ser = self.serializer_class(
            order_object, context={'request': request})
        return Response(order_ser.data, status=status.HTTP_200_OK)


class BankTypeSerializer(serializers.Serializer):
    gateway_type = serializers.ChoiceField(
        choices=['ZIBAL', 'BMI', 'SEP', 'ZARINPAL', 'IDPAY', 'BAHAMTA', 'MELLAT', 'PAYV1'])


class PaymentView(APIView):
    permission_classes = [IsAuthenticated]
    serializer_class = BankTypeSerializer

    @extend_schema(
        description="choices=['BMI', 'SEP', 'ZARINPAL', 'IDPAY', 'ZIBAL', 'BAHAMTA', 'MELLAT', 'PAYV1']",
        tags=['order payment']
    )
    def post(self, request):

        # Get user's cart
        cart = get_object_or_404(Cart, user=request.user)

        # Check if cart has items
        if not cart.items.exists():
            return Response(
                {'error': 'سبد خرید خالی است'},
                status=status.HTTP_400_BAD_REQUEST
            )

        # Check if cart has address
        if not cart.address:
            return Response(
                {'error': 'آدرس انتخاب نشده است'},
                status=status.HTTP_400_BAD_REQUEST
            )

        # Validate product variant quantities
        insufficient_stock_items = []
        adjusted_items = []

        for cart_item in cart.items.all():
            if cart_item.product_variant.in_stock < cart_item.quantity:
                available_stock = cart_item.product_variant.in_stock

                # Store info about insufficient stock
                insufficient_stock_items.append({
                    'product': cart_item.product_variant.product.name,
                    'variant': str(cart_item.product_variant),
                    'requested': cart_item.quantity,
                    'available': available_stock
                })

                # Auto-adjust the cart item quantity
                if available_stock > 0:
                    # Reduce quantity to available stock
                    cart_item.quantity = available_stock
                    cart_item.save()
                    adjusted_items.append({
                        'product': cart_item.product_variant.product.name,
                        'variant': str(cart_item.product_variant),
                        'new_quantity': available_stock
                    })
                else:
                    # Remove item if no stock available
                    product_name = cart_item.product_variant.product.name
                    variant_name = str(cart_item.product_variant)
                    cart_item.delete()
                    adjusted_items.append({
                        'product': product_name,
                        'variant': variant_name,
                        'new_quantity': 0,
                        'removed': True
                    })

        if insufficient_stock_items:
            # Create error message with product names
            product_names = [item['product']
                             for item in insufficient_stock_items]
            product_list = '، '.join(product_names)

            return Response({
                'detail': f'موجودی محصولات زیر کافی نیست: {product_list}',
                'message': 'تعداد محصولات به صورت خودکار تنظیم شد',
                'insufficient_items': insufficient_stock_items,
                'adjusted_items': adjusted_items
            }, status=status.HTTP_400_BAD_REQUEST)

        try:
            with transaction.atomic():
                # Compute special discounts for cart items if special_discount_code is applied
                special_total = 0
                for cart_item in cart.items.select_related('product_variant').all():
                    if cart.special_discount_code:
                        special_total += cart_item.special_discount_amount

                # Create order
                order = OrderModel.objects.create(
                    user=request.user,
                    address=cart.address,
                    created_at=timezone.now().date(),
                    discount_code=cart.discount_code,
                    special_discount_code=cart.special_discount_code,
                    discount_amount=cart.discount_code_amount,
                    special_discount_total=special_total,
                    tax=cart.tax_amount,
                    final_price=cart.final_price,
                    cart_total=cart.cart_total,
                    status='ADMIN_PENDING',
                    cart=cart
                )

                # Create order items and reduce product variant quantities
                for cart_item in cart.items.all():
                    OrderItemModel.objects.create(
                        order=order,
                        quantity=cart_item.quantity,
                        price=cart_item.product_variant.price,
                        product=cart_item.product_variant,
                        discount_percent=cart_item.discount,
                        special_discount_amount=cart_item.special_discount_amount
                    )

                    # Reduce product variant quantity
                    cart_item.product_variant.in_stock -= cart_item.quantity
                    cart_item.product_variant.save()

                # Reduce discount code quantity if used
                if cart.discount_code:
                    cart.discount_code.quantity -= 1
                    cart.discount_code.save()

                # Setup payment gateway
                user_mobile_number = request.user.phone
                factory = bankfactories.BankFactory()

                bank = factory.create(bank_models.BankType.ZIBAL)
                bank.set_request(request)
                # Use final_price instead of hardcoded amount
                bank.set_amount(cart.final_price)
                bank.set_client_callback_url(
                    'https://heymlz.com/transaction')
                bank.set_mobile_number(user_mobile_number)

                bank_record = bank.ready()
                # Link bank record to order (assuming you have this relationship)
                bank_record.order = order
                bank_record.save()

                return Response({
                    'url': bank.get_gateway()['url'],
                })

        except AZBankGatewaysException as e:
            print(f"Payment gateway error: {e}")
            return Response({
                'error': 'خطا در اتصال به درگاه پرداخت'
            }, status=status.HTTP_400_BAD_REQUEST)

        except Exception as e:
            print(f"Order creation error: {e}")
            return Response({
                'error': 'خطا در ثبت سفارش'
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


class BankCallbackSerializer(serializers.ModelSerializer):
    status_detail = serializers.SerializerMethodField()
    bank_type = serializers.SerializerMethodField()
    amount = serializers.SerializerMethodField()
    status = serializers.SerializerMethodField()

    class Meta:
        model = Bank
        fields = ['status', 'bank_type', 'tracking_code', 'amount',
                  'created_at', 'response_result', 'reference_number', 'status_detail']

    def get_status_detail(self, obj):
        with override('fa'):
            return obj.get_status_display()

    def get_bank_type(self, obj):
        with override('fa'):
            return obj.get_bank_type_display()

    def get_amount(self, obj):
        return f'{int(obj.amount):,.0f} تومان'

    def get_status(self, obj):
        if obj.status in {
            PaymentStatus.WAITING,
            PaymentStatus.REDIRECT_TO_BANK,
            PaymentStatus.RETURN_FROM_BANK,
        }:
            return "pending"
        elif obj.status in {
            PaymentStatus.CANCEL_BY_USER,
            PaymentStatus.EXPIRE_GATEWAY_TOKEN,
            PaymentStatus.EXPIRE_VERIFY_PAYMENT,
            PaymentStatus.ERROR,
        }:
            return "canceled"
        elif obj.status == PaymentStatus.COMPLETE:
            return "succeeded"
        return "unknown"


class CallbackView(APIView):
    serializer_class = BankCallbackSerializer
    permission_classes = [IsAuthenticated]

    def get(self, request, tracking_code):
        if not tracking_code:
            return Response({'detail': 'تریسکد خالی است.'}, status=status.HTTP_400_BAD_REQUEST)

        try:
            bank_record = bank_models.Bank.objects.get(
                tracking_code=tracking_code)

            permission = PaymentCallBackPermissions()
            if not permission.has_object_permission(request, self, bank_record):
                return Response({"detail": permission.message}, status=status.HTTP_403_FORBIDDEN)

            bank_record_ser = self.serializer_class(
                instance=bank_record, context={'request': request})

        except bank_models.Bank.DoesNotExist:
            return Response({'detail': 'کد تریسکد معتبر نمیباشد.'}, status=status.HTTP_404_NOT_FOUND)

        if bank_record.is_success:
            order = bank_record.order
            order.cart.clear_cart()
            order.is_paid = True
            order.save()
            return Response({"detail": "پرداخت با موفقیت انجام شد.", "bank_result": bank_record_ser.data}, status=status.HTTP_200_OK)
        else:
            order = bank_record.order
            order.rollback_stock()
        return Response(
            {
                "detail": "پرداخت ناموفق بود. در صورت کسر وجه، مبلغ حداکثر تا ۴۸ ساعت آینده به حساب شما بازگردانده می‌شود.",
                "bank_result": bank_record_ser.data,
            },
            status=status.HTTP_200_OK,
        )


class SetAddressSerilizer(serializers.Serializer):
    address_id = serializers.IntegerField()


class SetAddressForCartView(APIView):
    serializer_class = SetAddressSerilizer
    permission_classes = [IsAuthenticated, SetAddressPermissions]

    @extend_schema(
        tags=["order cart"]
    )
    def post(self, request):
        address_id = request.data.get('address_id', None)
        if not address_id:
            return Response({'detail': 'address_id را ارسال کنید'}, status=status.HTTP_400_BAD_REQUEST)
        address_object = get_object_or_404(UserAddressModel, pk=address_id)
        permission = SetAddressPermissions()
        if not permission.has_object_permission(request, self, address_object):
            return Response({"detail": permission.message}, status=status.HTTP_403_FORBIDDEN)

        cart_order, created = Cart.objects.get_or_create(
            user=request.user,
        )
        cart_order.address = address_object
        cart_order.save()
        return Response({'detail': 'ادرس با موفقیت انتخاب شد'})


from django.http import HttpResponse, HttpResponseForbidden, HttpResponseNotFound
from django.contrib.admin.views.decorators import staff_member_required
from django.contrib.auth.decorators import login_required
from .invoice_generator import generate_order_invoice, generate_shop_order_invoice


class UserOrderInvoiceView(APIView):
    """
    API endpoint for authenticated users to download their own order invoice PDF.
    Users can only download invoices for orders that belong to them.
    """
    permission_classes = [IsAuthenticated]

    @extend_schema(
        tags=["order invoice"],
        description="Download PDF invoice for the authenticated user's order.",
        responses={200: OpenApiTypes.BINARY},
    )
    def get(self, request, order_id):
        from .models import OrderModel

        try:
            order = OrderModel.objects.get(pk=order_id)
        except OrderModel.DoesNotExist:
            return Response(
                {'detail': 'سفارش مورد نظر یافت نشد'},
                status=status.HTTP_404_NOT_FOUND,
            )

        if order.user != request.user:
            return Response(
                {'detail': 'شما اجازه دسترسی به این فاکتور را ندارید'},
                status=status.HTTP_403_FORBIDDEN,
            )

        if not order.is_paid:
            return Response(
                {'detail': 'فاکتور فقط برای سفارش‌های پرداخت شده قابل دانلود است'},
                status=status.HTTP_400_BAD_REQUEST,
            )

        try:
            pdf_file = generate_order_invoice(order_id)
            response = HttpResponse(pdf_file.read(), content_type='application/pdf')
            response['Content-Disposition'] = f'attachment; filename="invoice_{order_id}.pdf"'
            return response
        except Exception as e:
            return Response(
                {'detail': f'خطا در ایجاد فاکتور: {str(e)}'},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


@login_required
def download_order_invoice(request, order_id):
    """
    Download invoice PDF for a specific OrderModel.
    Requires superuser permissions.
    """
    if not request.user.is_superuser:
        return HttpResponseForbidden("شما اجازه دسترسی به این فاکتور را ندارید")
    
    try:
        pdf_file = generate_order_invoice(order_id)
        
        response = HttpResponse(pdf_file.read(), content_type='application/pdf')
        response['Content-Disposition'] = f'attachment; filename="order_invoice_{order_id}.pdf"'
        
        return response
    except ValueError as e:
        return HttpResponseNotFound(f"خطا: {str(e)}")
    except Exception as e:
        return HttpResponse(f"خطا در ایجاد فاکتور: {str(e)}", status=500)


@login_required
def download_shop_order_invoice(request, shop_order_id):
    """
    Download invoice PDF for a specific ShopOrderModel.
    Shop owners can only download their own invoices, admins can download all.
    """
    from .models import ShopOrderModel
    
    try:
        shop_order = ShopOrderModel.objects.get(pk=shop_order_id)
        
        # Check permissions
        if not request.user.is_staff and not request.user.is_superuser:
            if not hasattr(request.user, 'shop') or request.user.shop != shop_order.shop:
                return HttpResponseForbidden("شما اجازه دسترسی به این فاکتور را ندارید")
        
        pdf_file = generate_shop_order_invoice(shop_order_id)
        
        response = HttpResponse(pdf_file.read(), content_type='application/pdf')
        response['Content-Disposition'] = f'attachment; filename="shop_order_invoice_{shop_order_id}.pdf"'
        
        return response
    except ShopOrderModel.DoesNotExist:
        return HttpResponseNotFound("فاکتور مورد نظر یافت نشد")
    except Exception as e:
        return HttpResponse(f"خطا در ایجاد فاکتور: {str(e)}", status=500)
