from django.shortcuts import render
from rest_framework import viewsets,status
from django.shortcuts import get_object_or_404
from product.views import FavProductViewSet
from .models import *
from .serializers import *
from rest_framework.response import Response
from .utils import * 
from sendgrid.helpers.mail import Mail
from sendgrid import SendGridAPIClient
from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist
from rest_framework.response import Response
from geopy.distance import geodesic
from product.serializers import ProductSer,BuyerProductSer, ProductListingSer
from product.models import Product,FavProduct, CategoriesPlan, PlanPurchase, Category, CategoriesPlanDuration
from rest_framework.decorators import action
from rest_framework.pagination import PageNumberPagination
from django.contrib import messages
from django.contrib.auth.hashers import check_password, make_password
from django.shortcuts import render, redirect
from rest_framework import viewsets, status
from rest_framework.permissions import AllowAny
from .custom_authentication import CustomJWTAuthentication 
from Help_Support.decorators import cache_response
from rest_framework_simplejwt.tokens import RefreshToken
from rest_framework.permissions import IsAuthenticated
from django.contrib.auth.models import Permission
from django.contrib.auth import authenticate
from rest_framework.views import APIView
from rest_framework.exceptions import ValidationError
from suscription.custom_pagination import CustomPagination
from django.db.models import Q, Subquery
from django.utils.timezone import now  # For getting the current date/time
from dateutil.relativedelta import relativedelta  # For date calculations
from django.db import IntegrityError
import logging
from wallet.models import ShoppingPoint
from vendor_listing.tasks import send_referrer_reward_email, send_referred_reward_email
from setting.views import *
from datetime import timedelta, datetime, time
import pytz




# ////////////////////////

from django.http import HttpResponse
from django.core.cache import cache


logger = logging.getLogger(__name__)


def test_redis(request):
    try:
        cache.set('test_key', 'test_value', timeout=10)
        value = cache.get('test_key')
        if value == 'test_value':
            return HttpResponse("Successfully connected to Redis")
        else:
            return HttpResponse("Failed to connect to Redis")
    except Exception as e:
        return HttpResponse(f"Error: {e}")

class VerifyReCaptcha(APIView):
    def post(self, request, *args, **kwargs):
        token = request.data.get("token")
        recaptcha_secret = settings.RECAPTCHA_SECRET_KEY

        if not token:
            return Response({"message": "reCAPTCHA token is required!"}, status=status.HTTP_400_BAD_REQUEST)

        response = requests.post(
            "https://www.google.com/recaptcha/api/siteverify",
            data={"secret": recaptcha_secret, "response": token},
        )

        result = response.json()
        if result.get("success"):
            return Response({"message": "reCAPTCHA verified!"})
        else:
            return Response({"message": "reCAPTCHA failed!"}, status=status.HTTP_400_BAD_REQUEST)
# //////////////////

def get_tokens_for_user(user):
    refresh = RefreshToken.for_user(user)

    return {
        'refresh': str(refresh),
        'access': str(refresh.access_token),
    }


class GroupCreateView(viewsets.ModelViewSet):

    queryset = Group.objects.all()
    serializer_class = GroupSerializer
    permission_classes=[AllowAny]
    # pagination_class = CustomPagination

class VendorUserPermissionViewSet(viewsets.ModelViewSet):
    # queryset = User.objects.filter(is_vendor = True)
    # queryset = Permission.objects.all()
    serializer_class = UserPermissionSer
    # pagination_class = CustomPagination

    def get_queryset(self):
        queryset = User.objects.filter(is_vendor = True)

        return queryset
    @cache_response()
    def list(self, request, *args, **kwargs):
        queryset = self.get_queryset().order_by('-id')
        # page = self.paginate_queryset(queryset)
        # if page is not None:
        #     serializer = self.get_serializer(page, many=True)
        #     return self.get_paginated_response(serializer.data)

        serializer = VendorProfileSer(queryset, many = True)

        return Response(serializer.data, status=status.HTTP_200_OK)
        

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data = request.data)  

        serializer.is_valid(raise_exception = True)

        # user_id = serializer.validated_data.get('user')
        # user = User.objects.filter(id = user_id)
        # Permission_id = serializer.validated_data.get('permission')

        serializer.save()

        return Response({'msg':'Permissions updated successfully'},status=status.HTTP_200_OK)


class AdminRegisterviewset(viewsets.ModelViewSet):
    queryset = User.objects.filter(is_superuser=True)
    serializer_class = AdminRegisterser
    # pagination_class = CustomPagination

    def create(self, request, *args, **kwargs):
        # Generate a strong password
        generated_password = generate_strong_password()
        data = request.data.copy()  # Make a copy of the request data
        data['password'] = generated_password  # Set the generated password
        serializer = self.serializer_class(data=data)
        serializer.is_valid(raise_exception=True)
        validated_data = serializer.validated_data
        # Create the superuser with the validated data
        admin_user = User.objects.create_superuser(email=validated_data['email'],
        password=generated_password )
        full_name = validated_data.get('full_name')
        if full_name:
            admin_user.full_name = full_name
            admin_user.save()
         # Send email with the password
        email = serializer.validated_data['email']
        subject = 'Your admin account credentials'
        body = f"""
            <p>Your admin account has been created successfully.</p>
            <p>
                <strong>Email:</strong> {email}<br>
                <strong>Password:</strong> {generated_password}
            </p>
            """
        html_content = '<a href="https://admin.e360mart.com/sign-in/" target="_blank">Login URL</a>'
        full_message = f"{body}</br></br>{html_content}"
        data = {
            'subject':subject,
            'body':full_message,
            'to_email':email
        }
        try:
          send_email(data)
        except Exception as e:
            return Response({'msg': 'Admin user created, but failed to send email. Error: {}'.format(e)}, status=status.HTTP_201_CREATED)
        # Return the response with the generated password
        return Response({
            'msg': 'Admin user created successfully',
            'password': generated_password
        }, status=status.HTTP_201_CREATED)
    @cache_response()
    def list(self, request, *args, **kwargs):
        queryset = self.get_queryset().order_by('-id')
        serializer = self.get_serializer(queryset, many=True)
        return Response({'msg': 'Admin list fetched successfully', 'data': serializer.data}, status=status.HTTP_200_OK)
    
    
class AdminLoginViewSet(viewsets.ModelViewSet):
    queryset = User.objects.filter(is_superuser=True) 
    serializer_class = AdminLoginSer
    # pagination_class = CustomPagination
    # permission_classes = [AllowAny]

    def create(self, request, *args, **kwargs):
        serializer = self.serializer_class(data = request.data)
        serializer.is_valid(raise_exception=True)
        
        email = serializer.validated_data.get('email') 
        password = serializer.validated_data.get('password') 
        
        admin_user = User.objects.filter(email = email,is_superuser=True).first()

        if admin_user == None:
            return Response({'msg':'Admin user with this email id not exist'},status=status.HTTP_404_NOT_FOUND)
        
        if not check_password(password,admin_user.password):
            return Response({'msg':'Incorrect password'},status=status.HTTP_400_BAD_REQUEST)

        admin_user_obj = User.objects.filter(email = email).first()

        admin_ser = UserProfileSerializer(admin_user_obj)

        token = get_tokens_for_user(admin_user_obj)

        return Response({'msg':'Login successful', 'token':token, 'data':admin_ser.data},status=status.HTTP_200_OK) 
    @cache_response()
    def list(self, request, *args, **kwargs):
        queryset = User.objects.filter(is_vendor = False, is_buyer = False)

        serializer = self.serializer_class(queryset, many=True)

        return Response(serializer.data,status=status.HTTP_200_OK)

class AdminPasswordResetRequestViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = AdminPasswordResetRequestSer
    # pagination_class = CustomPagination
    # permission_classes = [AllowAny]

    def create(self, request, *args, **kwargs):
        serializer = self.serializer_class(data = request.data)
        serializer.is_valid(raise_exception=True)
        email = serializer.validated_data.get('email')
        admin_user = User.objects.filter(email = email).first()

        if admin_user == None:
            return Response({'msg':'Email not registered. Please sign up.'},status=status.HTTP_404_NOT_FOUND)

        # Generate OTP
        otp = generate_otp()
        # GenerateOTP.objects.create(admin_user = admin_user, otp = otp)

        admin_user.otp = otp
        
        admin_user.save()

        # Send OTP via Email
        body = 'OTP is : '+ otp

        data = {
            'subject':'e360 Mart OTP for Admin password reset',
            'body':body,
            'to_email':email,
            'otp':otp
        }

        send_email_otp(data)

        return Response({'msg':f'OTP sent on {email} for admin password reset', 'otp':otp},status=status.HTTP_200_OK)



class AdminPasswordResetViewSet(viewsets.ViewSet):
    # queryset = AdminUser.objects.all()
    serializer_class = AdminPasswordResetSer
    # pagination_class = CustomPagination
    # permission_classes = [AllowAny]

    def create(self, request, *args, **kwargs):
        # otp = request.data.pop('otp')
        serializer = self.serializer_class(data = request.data)
        serializer.is_valid(raise_exception=True)

        email = serializer.validated_data.get('email')
        password = serializer.validated_data.get('password')
        confirm_password = serializer.validated_data.get('confirm_password')
    

        admin_user = User.objects.get(email = email)
        # otp_obj = GenerateOTP.objects.filter(admin_user = admin_user, otp=otp).first()
     
        if admin_user.otp_verified == False:
            return Response({'msg': 'OTP not verified'}, status=status.HTTP_400_BAD_REQUEST)
        if password != confirm_password:
            return Response({'msg': 'Password and confirm password does not match.'}, status=status.HTTP_400_BAD_REQUEST)
            
    
        admin_user.set_password(password)
        admin_user.save()
        return Response({'msg':f'Password reset successfully '},status=status.HTTP_200_OK)
       
        

   


# ***** Vendor
class VendorRegisterViewSet(viewsets.ModelViewSet):
    queryset = User.objects.filter(is_vendor=True)
    serializer_class = VendorRegisterSer
    # pagination_class = CustomPagination

    def create(self, request, *args, **kwargs):

        data = request.data.copy()  # Make a mutable copy of the request data
       
        # if 'image' in data and data['image']:
        #     # Check if the uploaded file is a valid image
        #     image_data = data['image']
        #     image_format = imghdr.what('', h=image_data.read())
        #     if not image_format:
        #         return Response({'msg': 'Please select a valid image'}, status=status.HTTP_400_BAD_REQUEST)
            
        #     # Reset the file pointer for further processing
        #     image_data.seek(0)

        #     # Check if the uploaded file is an image using PIL
        #     try:
        #         image = Image.open(image_data)
        #         image.verify()  # Attempt to open and verify the image file
        #     except (IOError, SyntaxError) as e:
        #         return Response({'error': 'Please select a valid image'}, status=status.HTTP_400_BAD_REQUEST)
        #     finally:
        #         image_data.seek(0)

        serializer = self.get_serializer(data = request.data)
        serializer.is_valid(raise_exception = True)

        email = serializer.validated_data.get('email')

        otp = generate_otp()

        vendor = serializer.save()

        vendor.otp = otp

        # vendor.set_password(vendor.password)
        vendor.is_active = False

        vendor.save()
        # Send OTP on Email
        body = 'OTP is : '+ otp
        data = {
            'subject':'e360 Mart OTP for Registration',
            'body':body,
            'to_email':email,
            'otp':otp 
        }
        
        try:
            send_email_otp(data)
        except Exception as e:
            return Response({'error':f"\n  ***** {e} ***** \n"})
        token = get_tokens_for_user(vendor) 

        # Prepare the response data
        response_data = {
            'msg': 'OTP sent successfully',
            'token': token
            # 'vendor': {
            #     'id': vendor.id,
            #     'email': vendor.email,
            #     'is_active': vendor.is_active,
            # }
        }
        return Response(response_data, status=status.HTTP_200_OK)
        # return Response({'msg':'OTP sent successfully'},status=status.HTTP_200_OK)
    
    # def partial_update(self, request, *args, **kwargs):
    #     instance = self.get_object()
    #     print("==========Vendor Update=========")
    #     print(f"API called for partial update by user {request.user.id} with data: {request.data}")
        


    #     data = request.data.copy()  # Create a mutable copy
    #     main_category_id = data.pop('main_category', None)  # Remove from data safely

    #     # Convert 'lat' and 'long' to float
    #     if 'lat' in data:
    #         try:
    #             data['lat'] = float(data['lat'])
    #         except ValueError:
    #             raise ValidationError("Invalid latitude value.")

    #     if 'long' in data:
    #         try:
    #             data['long'] = float(data['long'])
    #         except ValueError:
    #             raise ValidationError("Invalid longitude value.")

    #     serializer = self.get_serializer(instance, data=data, partial=True)
    #     # serializer.is_valid(raise_exception=True)
    #     try:
    #         serializer.is_valid(raise_exception=True)
    #     except ValidationError as e:
    #         return Response({"message": " ",  "error": "An error occurred while updating the document."}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
    #         print(f"Validation error: {e.detail} for user {request.user.id}")

    #     if 'is_document' in data:
    #         instance.is_document = data['is_document']

    #         try:
    #             vendor = serializer.save()
    #             print(f"Document updated successfully for user {request.user.id}")

    #             data = {
    #                 'subject': 'e360 Mart: Account under verification',
    #                 'name': instance.full_name,
    #                 'to_email': instance.email
    #             }
    #             send_user_verify(data)
    #             print(f"Verification email sent to {instance.email}")

    #             token = get_tokens_for_user(vendor)

    #             response_data = {
    #                 'msg': 'Documents are uploaded successfully!',
    #                 'token': token,
    #                 'user_data': serializer.data
    #             }
                
    #         except Exception as e:
    #             print("==========Error==========")
    #             print(f"Error updating document for user {request.user.id}: {str(e)}")
    #             return Response({"error": "An error occurred while updating the document."}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    def partial_update(self, request, *args, **kwargs):
        instance = self.get_object()
        print("==========Vendor Update=========")
        print(f"API called for partial update by user {request.user.id} with data: {request.data}")

        # Manually extract needed fields from request.data
        data = {}
        for key in request.data:
            data[key] = request.data[key]

        main_category_id = data.pop('main_category', None)

        print('data----------', data)
        print('main_category_id----------', main_category_id)

        # Convert 'lat' and 'long' to float if present
        if 'lat' in data:
            try:
                data['lat'] = float(data['lat'])
            except ValueError:
                raise ValidationError("Invalid latitude value.")

        if 'long' in data:
            try:
                data['long'] = float(data['long'])
            except ValueError:
                raise ValidationError("Invalid longitude value.")

        serializer = self.get_serializer(instance, data=data, partial=True)

        try:
            serializer.is_valid(raise_exception=True)
        except ValidationError as e:
            logger.error(f"Validation error: {e.detail} for user {request.user.id}")
            return Response({
                "message": "Validation failed.",
                "error": e.detail
            }, status=status.HTTP_400_BAD_REQUEST)

        if 'is_document' in data:
            instance.is_document = data['is_document']

            try:
                vendor = serializer.save()
                logger.info(f"Document updated successfully for user {request.user.id}")

                # Optional: send verification email
                email_data = {
                    'subject': 'e360 Mart: Account under verification',
                    'name': instance.full_name,
                    'to_email': instance.email
                }
                send_user_verify(email_data)
                logger.info(f"Verification email sent to {instance.email}")

                token = get_tokens_for_user(vendor)

                response_data = {
                    'msg': 'Documents are uploaded successfully!',
                    'token': token,
                    'user_data': serializer.data
                }

                main_category = main_category_id

                logger.info(f"Main Category {main_category}")
                logger.info(f"Main Category Id {main_category_id}")


                if main_category_id :

                    main_category_id = int(main_category_id[0]) if isinstance(main_category_id, list) else int(main_category_id)
                    main_category = MainCategory.objects.get(id=main_category_id)

                    if main_category :
                        categories_plan = CategoriesPlan.objects.filter(main_category=main_category, name='FREE').first()

                        category_duration = CategoriesPlanDuration.objects.filter(category_plan=categories_plan).first()

                        existing_plan = PlanPurchase.objects.filter(
                            vendor=vendor, main_category=main_category, status='active', payment_status="successful"
                        ).exists()

                        if not existing_plan:

                            start_date = now().date()
                            end_date = start_date + relativedelta(months=3)

                            product_limit = category_duration.product_limit if category_duration.product_limit else 1

                            purchase = PlanPurchase.objects.create(
                                vendor=vendor,
                                main_category=main_category,
                                categories_plan=categories_plan,
                                plan_duration=category_duration,
                                duration_months=3,
                                product_limit=product_limit,
                                amount=serializer.validated_data.get('amount', 0.00),
                                start_date=start_date,
                                end_date=end_date,
                                payment_status=serializer.validated_data.get('payment_status', 'successful'),
                                status='active'
                            )

                return Response(response_data, status=status.HTTP_200_OK)

            except Exception as e:
                logger.error(f"Error updating document for user {request.user.id}: {str(e)}")
                return Response({"error": "An error occurred while updating the document."}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

            # if 'is_document' in request.data:
            #     instance.is_document = request.data['is_document']
            #     # serializer.save()
            #     vendor = serializer.save()
            #     # body=f'Your account is under admin verification. Please wait till admin approval'
            #     print(f"Document updated successfully for user {request.user.id}")
            #     data = {
            #         'subject': 'e360 Mart: Account under verification',
            #         'name': instance.full_name,
            #         'to_email': instance.email
            #     }
            #     send_user_verify(data)
            #     token = get_tokens_for_user(vendor) 

            #     # Prepare the response data
            #     response_data = {
            #         'msg': 'Documents are uploaded successfully!',
            #         'token': token,
            #         'user_data':serializer.data
            #     }
            #     print(f"Response data: {response_data}")
            #     return Response(response_data, status=status.HTTP_200_OK)
                # return Response({'msg':'Documents are uploaded successfully!','user_data':serializer.data},status=status.HTTP_200_OK)    
        else:    
            vendor = serializer.save()
            token = get_tokens_for_user(vendor) 

            # Prepare the response data
            response_data = {
                'msg': 'Your profile updated successfully',
                'token': token,
                'user_data':serializer.data
            }
            return Response(response_data, status=status.HTTP_200_OK)
            return Response({'msg':'Your profile updated successfully','user_data':serializer.data},status=status.HTTP_200_OK)
     


class FreePlanPurchaseView(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request):
        vendor = request.user 

        if not vendor.is_vendor :
            return Response({"status":False, "error": "Only vendor has purchase subscription."}, status=status.HTTP_400_BAD_REQUEST)

        main_category_id = request.data.get('main_category')
        if not main_category_id:
            return Response({"status":False, "error": "Main category is required."}, status=status.HTTP_400_BAD_REQUEST)

        try:
            main_category_id = int(main_category_id[0]) if isinstance(main_category_id, list) else int(main_category_id)
            main_category = MainCategory.objects.get(id=main_category_id)
        except MainCategory.DoesNotExist:
            return Response({"status":False, "error": "Invalid main category ID."}, status=status.HTTP_400_BAD_REQUEST)

        categories_plan = CategoriesPlan.objects.filter(main_category=main_category, name='FREE').first()
        if not categories_plan:
            return Response({"status":False, "error": "Free plan not available for this category."}, status=status.HTTP_404_NOT_FOUND)

        existing_plan = PlanPurchase.objects.filter(
            vendor=vendor, main_category=main_category, status='active', payment_status="successful"
        ).exists()

        if existing_plan:
            return Response({"status":False, "error": "You already have an active plan for this category."}, status=status.HTTP_400_BAD_REQUEST)

        start_date = now().date()
        end_date = start_date + relativedelta(months=3)

        purchase = PlanPurchase.objects.create(
            vendor=vendor,
            main_category=main_category,
            categories_plan=categories_plan,
            duration_months=1,
            product_limit=1,
            amount=0.00,  
            start_date=start_date,
            end_date=end_date,
            payment_status="successful",
            status="active"
        )

        return Response(
            {"status":True, "message": "Free plan purchased successfully.", "plan_id": purchase.id},
            status=status.HTTP_201_CREATED
        )

class VendorListing(viewsets.ViewSet):
    permission_classes = [IsAuthenticated]
    serializer_class = VendorRegisterSer
    pagination_class = CustomPagination

    def list(self, request, *args, **kwargs):
        if not request.user.is_superuser or not request.user.otp_verified:
            return Response(
                {'detail': 'Only Admin Can Access This Endpoint'}, 
                status=status.HTTP_403_FORBIDDEN
            )

        search = request.query_params.get('search')
        start_date = request.query_params.get('start_date')
        end_date = request.query_params.get('end_date')

        queryset = User.objects.filter(is_vendor=True)

        if search:
            queryset = queryset.filter(
                Q(full_name__icontains=search) | 
                Q(phone__icontains=search) | 
                Q(email__icontains=search)
            )

        # if start_date and end_date:
        #     queryset = queryset.filter(created_at__date__range=[start_date, end_date])

        if start_date and end_date:
            # Parse to ensure correct format
            # try:
            #     start_dt = datetime.strptime(start_date, '%Y-%m-%d')
            #     end_dt = datetime.strptime(end_date, '%Y-%m-%d') + timedelta(days=1)  # include full end day

            #     queryset = queryset.filter(created_at__range=(start_dt, end_dt))
            #     logger.info(f'Final query: { queryset.query}')
            # except ValueError:
            #     logger.info('Invalid datetime format.')
            tz = pytz.timezone("Africa/Dar_es_Salaam")

            try:
                start_dt = tz.localize(datetime.combine(datetime.strptime(start_date, '%Y-%m-%d').date(), time.min))
                end_dt = tz.localize(datetime.combine(datetime.strptime(end_date, '%Y-%m-%d').date(), time.max))

                queryset = queryset.filter(created_at__range=(start_dt, end_dt))
                logger.info(f'Final query: {queryset.query}')
            except ValueError:
                logger.info('Invalid datetime format.')
       
        paginator = self.pagination_class()
        paginated_vendor = paginator.paginate_queryset(queryset, request, view=self)
        serializer = self.serializer_class(
            paginated_vendor, 
            many=True, 
            context={'request': request, 'user': request.user}
        )

        return paginator.get_paginated_response(serializer.data)

class VendorOTPVerifyViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = VendorRegisterOTPVerifySer
    # pagination_class = CustomPagination

    def create(self, request, *args, **kwargs):

        serializer = self.get_serializer(data = request.data)
        serializer.is_valid(raise_exception = True)

        email = serializer.validated_data.get('email')
        otp = int(serializer.validated_data.get('otp'))

        vendor_user = User.objects.filter(email = email).first()

        if vendor_user == None:
            return Response({'error':f'User with this email does not exist'},status=status.HTTP_404_NOT_FOUND)

        if vendor_user.otp != otp:

            return Response({'error':'Invalid OTP'},status=status.HTTP_400_BAD_REQUEST)
        
        #vendor_user.is_active=True
        vendor = UserProfileSerializer(vendor_user)
        stored_otp = vendor_user.otp
        if stored_otp == otp:   
            # vendor_user.set_password(password)
            vendor_user.otp_verified = True
            vendor_user.save()
        # vendor_user.save()

        token = get_tokens_for_user(vendor_user) 

        # Prepare the response data
        response_data = {
            'msg': 'OTP verified successfully',
            'token': token,
            'data':vendor.data
        }
        return Response(response_data, status=status.HTTP_200_OK)

        return Response({'msg':'OTP verified successfully','data':vendor.data},status=status.HTTP_200_OK)

    

class VendorLoginViewSet(viewsets.ViewSet):
    queryset = User.objects.all()
    serializer_class = VendorLoginSer
    # pagination_class = CustomPagination

    def get_serializer_context(self):
        context = super().get_serializer_context()
        context['request'] = self.request
        return context
    
    def create(self, request, *args, **kwargs):
        serializer = self.serializer_class(data = request.data,context={'request': request})
        serializer.is_valid(raise_exception=True)
    
        email = serializer.validated_data.get('email')
        password = serializer.validated_data.get('password')

        vendor_user = User.objects.filter(email = email).first()
        document_data = UserProfileSerializer(vendor_user,context={'request':request})
        if vendor_user == None:
            return Response({'msg':'Vendor user with this email id not exist'},status=status.HTTP_404_NOT_FOUND)
        if vendor_user.is_buyer==True:
            return Response({"msg":"It seems you don't have an account here. Please create an account as a vendor using a different email that is not used on user app"},status=status.HTTP_404_NOT_FOUND)
        if vendor_user.is_superuser==True:
            return Response({"msg":"Admin accounts cannot log in as vendors. Please use a different email that isn't associated with an admin account."},status=status.HTTP_403_FORBIDDEN)
        if not check_password(password,vendor_user.password):
            return Response({'msg':'Incorrect password'},status=status.HTTP_400_BAD_REQUEST)
        if vendor_user.otp_verified == False:
            return Response({'msg': 'OTP not verified'}, status=status.HTTP_400_BAD_REQUEST)
        
        if vendor_user.is_document==False:  
            return Response({'error':'Your documents are not complete',"document_data":document_data.data},status=status.HTTP_400_BAD_REQUEST)
        if vendor_user.is_active==False and vendor_user.is_staff==False:
            return Response({'error':f'Your account is under admin verification. Please wait till admin approval'},status=status.HTTP_400_BAD_REQUEST)
        
        if vendor_user.is_active==False and vendor_user.is_staff==True:  
            body=f'Your account is rejected.  Reason is : {vendor_user.reason}'
            data = {
                'subject': 'Account rejected',
                'body': body,
                'to_email': email
            }

            send_email_to_client(data)
            return Response({'error':f'Your account is rejected.  Reason is : {vendor_user.reason}','data':document_data.data},status=status.HTTP_400_BAD_REQUEST)
        
        if vendor_user.is_staff==False:
            return Response({'error':'Your is not approved by admin'},status=status.HTTP_400_BAD_REQUEST)
        
        vendor_user_obj = User.objects.filter(email = email).first()

        vendor_ser = UserProfileSerializer(vendor_user_obj,context={'request':request})

        token = get_tokens_for_user(vendor_user_obj)

        return Response({'msg':'Login successful','token':token, 'data':vendor_ser.data},status=status.HTTP_200_OK) 



class VendorPasswordResetRequestViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = VendorPasswordResetRequestSer
    # pagination_class = CustomPagination
    # permission_classes = [AllowAny]

    def create(self, request, *args, **kwargs):

        serializer = self.serializer_class(data = request.data)
        serializer.is_valid(raise_exception=True)

        email = serializer.validated_data.get('email')
        # phone_no = serializer.validated_data.get('phone')

        # vendor_user = User.objects.filter(email = email, phone = phone_no).first()
        vendor_user = User.objects.filter(email = email).first()

        if vendor_user == None:
            return Response({'msg':'Vendor user with this credentials does not exist'},status=status.HTTP_404_NOT_FOUND)

        # Generate OTP
        otp = generate_otp()
        # GenerateOTP.objects.create(admin_user = admin_user, otp = otp)

        vendor_user.otp = otp
        
        vendor_user.save()

        # Send OTP via Email
        body = 'OTP is : '+ otp

        data = {
            'subject':'e360 Mart OTP for Vendor Password Reset',
            'body':body,
            'to_email':email,
            'otp':otp
        }
    
        send_email_otp(data)

        return Response({'msg':f'OTP sent sucessfully', 'otp':otp},status=status.HTTP_200_OK)



class VendorPasswordResetOTPVerifyViewSet(viewsets.ViewSet):
    # queryset = AdminUser.objects.all()
    serializer_class = VendorPasswordResetOTPVerifySer
    # pagination_class = CustomPagination
    # permission_classes = [AllowAny]

    def create(self, request, *args, **kwargs):
        # otp = request.data.pop('otp')
        serializer = self.serializer_class(data = request.data)
        serializer.is_valid(raise_exception=True)

        email = serializer.validated_data.get('email')
        otp = int(serializer.validated_data.get('otp'))

        vendor_user = User.objects.get(email = email)
        # otp_obj = GenerateOTP.objects.filter(admin_user = admin_user, otp=otp).first()
        stored_otp = vendor_user.otp

        if stored_otp == otp:   
            # vendor_user.set_password(password)
            vendor_user.otp_verified = True
            vendor_user.save()
            return Response({'msg':f' OTP verified successfully'},status=status.HTTP_200_OK)
        else:
            return Response({'msg':'Incorrect OTP'},status=status.HTTP_400_BAD_REQUEST)


class VendorPasswordResetViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = VendorPasswordResetSer
    # pagination_class = CustomPagination

    def create(self, request, *args, **kwargs):
        serializer = self.serializer_class(data = request.data)
        serializer.is_valid(raise_exception=True)

        email = serializer.validated_data.get('email')
        password = serializer.validated_data.get('password')
        confirm_password = serializer.validated_data.get('confirm_password')

        vendor_obj = User.objects.filter(email = email).first()

        if vendor_obj.otp_verified == False:
            return Response({'error':'Incorrect OTP'},status=status.HTTP_400_BAD_REQUEST)
        
        vendor_obj.set_password(password)
  
        vendor_obj.save()

        return Response({'msg':f'Password reset successfully'},status=status.HTTP_200_OK)
    
class VendorSubscriptionProductwise(APIView) :
    permission_classes = [IsAuthenticated]

    def post(self, request):
        vendors_without_plan = User.objects.filter(
            is_vendor=True
        ).exclude(
            id__in=Subquery(PlanPurchase.objects.values('vendor'))
        )

        try:
            response_data = []
            for vendor in vendors_without_plan:
                logger.info(f'Processing vendor ID: {vendor.id}')

                category_ids = Product.objects.filter(user=vendor.id).values_list('category_id', flat=True).distinct()

                if category_ids:
                    main_category_ids = Category.objects.filter(
                        id__in=category_ids
                    ).values_list('main_category_id', flat=True).distinct()

                    main_category_ids = list(filter(None, main_category_ids))
                    logger.info(f'Main category IDs for vendor {vendor.id}: {main_category_ids}')

                    if len(set(main_category_ids)) > 1:
                        main_category_id = 5
                    elif main_category_ids:
                        main_category_id = main_category_ids[0]
                    else:
                        main_category_id = None

                else :
                    main_category_id = 5

                if not main_category_id:
                    logger.warning(f'No main category found for vendor {vendor.id}')
                    continue

                main_category = MainCategory.objects.get(id=main_category_id)

                vendor.main_category = main_category
                vendor.save()

                logger.info(f'Main category assigned to vendor {vendor.id}: {main_category}')

                categories_plan = CategoriesPlan.objects.filter(main_category=main_category, name='FREE').first()
                if not categories_plan:
                    logger.error(f'Free plan not available for category {main_category.id}')
                    continue

                existing_plan = PlanPurchase.objects.filter(
                    vendor=vendor,
                    main_category=main_category,
                    status='active',
                    payment_status='successful'
                ).exists()

                

                if existing_plan:
                    logger.warning(f'Active plan already exists for vendor {vendor.id} and category {main_category.id}')
                    continue

                start_date = now().date()
                end_date = start_date + relativedelta(months=3)

                product_count = Product.objects.filter(user=vendor.id, payment_status='paid').count()


                category_duration = CategoriesPlanDuration.objects.filter(
                    category_plan=categories_plan
                ).first()

                if not category_duration:
                    logger.warning(f"No duration found for FREE plan ID {categories_plan.id}")
                    continue

                product_limit = category_duration.product_limit or 1

                PlanPurchase.objects.create(
                    vendor=vendor,
                    main_category=main_category,
                    categories_plan=categories_plan,
                    plan_duration=category_duration,
                    duration_months=3,
                    product_limit=product_limit,
                    products_added=product_count,
                    amount=0.00,
                    start_date=start_date,
                    end_date=end_date,
                    # payment_status='successful',
                    payment_status=PlanPurchase.PaymentStatus.SUCCESS,
                    status='active'
                )

                logger.info(f'Free plan successfully created for vendor {vendor.id}')

                response_data.append({
                    "vendor_id": vendor.id,
                    "vendor_name": vendor.get_full_name() or vendor.full_name,
                    "main_category": {
                        "id": main_category.id,
                        "name": main_category.name,
                    }
                })

            return Response({
                'msg': 'Vendors successfully subscribed to free plan',
                'data': response_data
            }, status=status.HTTP_200_OK)

        except Exception as e:
            logger.error(f'Unexpected error: {str(e)}', exc_info=True)
            return Response({"error": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        
    
class VendorSubscriptionwiseProductActive(APIView) :
    permission_classes = [IsAuthenticated]

    def post(self, request):

        plan_purchase = PlanPurchase.objects.filter(payment_status="successful", status="active")

        logger.info(f'PlanPurchase IDs: {plan_purchase}')

        try:
            response_data = []
            for plan in plan_purchase:

                vendor_id = plan.vendor.id

                logger.info(f'Processing subscription ID: {plan.id}')
                logger.info(f'Processing vendor ID: {vendor_id}')

                active_paid_products = Product.objects.filter(
                    user_id=vendor_id,
                    payment_status="paid",
                    status="active"
                ).order_by('-id')  

                active_paid_count = active_paid_products.count()

                product_limit = plan.product_limit

                logger.info('🧑‍💼 active product count: %s', active_paid_count)
                logger.info('🧑‍💼 new plan limit: %s', product_limit)
                logger.info('🧑‍💼 new active plan count: %s', active_paid_count)
                extra_product_ids = []
                boosted_ids = []
                activate_product_ids = []

                if active_paid_count > product_limit:
                    extra_count = active_paid_count - product_limit
                    extra_product_ids = list(
                        active_paid_products.values_list('id', flat=True)[:extra_count]
                    )
                    logger.info('🧑‍💼 deactivate products: %s', extra_product_ids)
                    Product.objects.filter(id__in=extra_product_ids).update(status="inactive")
                else :
                    if active_paid_count != 0 :
                        missing_count = product_limit - active_paid_count
                        inactive_paid_products = Product.objects.filter(
                            user_id=vendor_id,
                            payment_status="paid",
                            status="inactive"
                        ).order_by('id')[:missing_count]

                        activate_product_ids = list(inactive_paid_products.values_list('id', flat=True))
                        logger.info('🧑‍💼 reactivate products: %s', activate_product_ids)
                        Product.objects.filter(id__in=activate_product_ids).update(status="active")

                if plan and plan.plan_duration and plan.plan_duration.category_plan.name.upper() != 'FREE':
                    boosted_limit = plan.plan_duration.boost_product_limit

                    if boosted_limit:
                        logger.info('🧑‍💼 Boosted Limit: %s', boosted_limit)
                        
                        boosted_products = Product.objects.filter(
                            user_id=vendor_id,
                            payment_status="paid",
                            availability_status="available",
                            status="active",
                            is_boosted=False
                        ).order_by('-id')[:boosted_limit]

                        boosted_ids = list(boosted_products.values_list('id', flat=True))
                        if boosted_ids:
                            Product.objects.filter(id__in=boosted_ids).update(is_boosted=True)
                            logger.info('✅ Boosted product IDs: %s', boosted_ids)

                new_active_paid_count = Product.objects.filter(
                    user_id=vendor_id,
                    payment_status="paid",
                    status="active"
                ).count()

                plan.product_added = new_active_paid_count
                plan.save()


                response_data.append({
                    "vendor_id": vendor_id,
                    "plan": {
                        "id": plan.id,
                        "limit": product_limit,
                        "added_product":new_active_paid_count,
                        "name": plan.plan_duration.name if plan.plan_duration else None,
                        "inactivated_products": extra_product_ids or None,
                        "activated_products": activate_product_ids or None,
                        "boosted_products": boosted_ids or None
                    }
                })

            return Response({
                'msg': 'Vendors successfully subscribed to free plan',
                'data': response_data
            }, status=status.HTTP_200_OK)

        except Exception as e:
            logger.error(f'Unexpected error: {str(e)}', exc_info=True)
            return Response({"error": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


class BuyerReferralCodeGenerate(APIView) :  
    permission_classes = [IsAuthenticated]

    def post(self, request):

        buyers = User.objects.filter(is_buyer=True, referral_code__isnull=True)

        logger.info(f'buyers IDs: {buyers}')

        try:
            response_data = []
            for buyer in buyers:

                buyer.referral_code = generate_unique_referral_code()
                buyer.save()

                logger.info(f'Processing buyer ID: {buyer.id} and their referral code : {buyer.referral_code}')

                response_data.append({
                    "buyer_id": buyer.id,
                    "code": buyer.referral_code,
                })
                

            return Response({
                'msg': 'Buyer referral code generate successfully',
                'data': response_data
            }, status=status.HTTP_200_OK)

        except Exception as e:
            logger.error(f'Unexpected error: {str(e)}', exc_info=True)
            return Response({"error": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)



# ***** Buyer Register
class BuyerRegisterViewSet(viewsets.ModelViewSet):
    queryset = User.objects.filter(is_buyer=True)
    serializer_class = BuyerRegisterSer
    # pagination_class = CustomPagination

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data = request.data)
        serializer.is_valid(raise_exception = True)

        email = serializer.validated_data.get('email')
        otp = generate_otp()

        buyer = serializer.save()

        buyer.otp = otp

        # buyer.set_password(buyer.password)
        buyer.is_active = False
        buyer.save()

        # Send OTP on Email
        body = 'OTP is : '+ otp

        data = {
            'subject':'e360 Mart OTP for Registration',
            'body':body,
            'to_email':email,
            'otp':otp
        }
        
        send_email_otp(data)

        return Response({'msg':'OTP sent successfully'},status=status.HTTP_200_OK)
    
    def partial_update(self, request, *args, **kwargs):
        instance = self.get_object()
        serializer = self.get_serializer(instance, data=request.data, partial=True)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        query_params = request.query_params
        is_login = query_params.get('is_login', None)
        
        response_data = {
            'msg': 'User data updated successfully',
            'data': serializer.data,
        }

        if is_login:
            # Generate the token for the user using the custom function
            token = get_tokens_for_user(instance)
            response_data['token'] = token

        return Response(response_data, status=status.HTTP_200_OK)
        # return Response({'msg':'User data updated successfully','user_data':serializer.data},status=status.HTTP_200_OK)
    


class BuyerListing(viewsets.ViewSet):
    permission_classes = [IsAuthenticated]
    serializer_class = BuyerRegisterSer
    pagination_class = CustomPagination

    def list(self, request, *args, **kwargs):
        if not request.user.is_superuser or not request.user.otp_verified:
            return Response(
                {'detail': 'Only Admin Can Access This Endpoint'}, 
                status=status.HTTP_403_FORBIDDEN
            )

        search = request.query_params.get('search')
        start_date = request.query_params.get('start_date')
        end_date = request.query_params.get('end_date')

        queryset = User.objects.filter(is_buyer=True)

        if search:
            queryset = queryset.filter(
                Q(full_name__icontains=search) | 
                Q(phone__icontains=search) | 
                Q(email__icontains=search)
            )

        # if start_date and end_date:
        #     queryset = queryset.filter(created_at__date__range=[start_date, end_date])

        if start_date and end_date:
            # Parse to ensure correct format
            # try:
            #     start_dt = datetime.strptime(start_date, '%Y-%m-%d')
            #     end_dt = datetime.strptime(end_date, '%Y-%m-%d') + timedelta(days=1)  # include full end day

            #     queryset = queryset.filter(created_at__range=(start_dt, end_dt))
            #     logger.info(f'Final query: { queryset.query}')
            # except ValueError:
            #     logger.info('Invalid datetime format.')
            
            tz = pytz.timezone("Africa/Dar_es_Salaam")

            # Step 1: Localize in Africa/Dar_es_Salaam
            start_local = tz.localize(datetime.combine(datetime.strptime(start_date, '%Y-%m-%d').date(), time.min))
            end_local = tz.localize(datetime.combine(datetime.strptime(end_date, '%Y-%m-%d').date(), time.max))

            # Step 2: Convert to UTC for DB filtering
            start_utc = start_local.astimezone(pytz.utc)
            end_utc = end_local.astimezone(pytz.utc)

            # Step 3: Apply filter
            queryset = queryset.filter(created_at__range=(start_utc, end_utc))

        paginator = self.pagination_class()
        paginated_buyer = paginator.paginate_queryset(queryset, request, view=self)
        serializer = self.serializer_class(
            paginated_buyer, 
            many=True, 
            context={'request': request, 'user': request.user}
        )

        return paginator.get_paginated_response(serializer.data)


class BuyerOTPVerifyViewSet(viewsets.ModelViewSet): 
    queryset = User.objects.all() 
    serializer_class = BuyerRegisterOTPVerifySer
    # pagination_class = CustomPagination

    def create(self, request, *args, **kwargs):

        try:
            serializer = self.get_serializer(data=request.data)
            serializer.is_valid(raise_exception=True)

            email = serializer.validated_data.get('email')
            otp = serializer.validated_data.get('otp')

            buyer_user = User.objects.filter(email=email).first()

            if not buyer_user:
                logger.info(f"[OTP Log] - No user found with email: {email}")
                return Response({'msg': 'User not found'}, status=status.HTTP_404_NOT_FOUND)

            if buyer_user.otp != otp:
                logger.info(f"[OTP Log] - Invalid OTP entered for email: {email}")
                return Response({'msg': 'Invalid OTP'}, status=status.HTTP_200_OK)

            buyer_user.otp_verified = True
            buyer_user.is_active = True
            buyer_user.is_staff = True
            buyer_user.save()

            logger.info(f"[OTP Log] - OTP verified successfully for user: {email}")


            # if buyer_user.referred_by:

            #     referrer_points = int(get_setting_value('referrer_reward_points'))
            #     referred_points = int(get_setting_value('referred_user_reward_points'))

            #     logger.info(f"Referrer - {buyer_user.referred_by}")

            #     referrer_point_exists = ShoppingPoint.objects.filter(
            #         user=buyer_user.referred_by,
            #         source_user=buyer_user,
            #         transaction_type='credit'
            #         # description="Referral reward"
            #     ).exists()

            #     logger.info(f"referrer_point_exists - {referrer_point_exists}")

            #     if not referrer_point_exists:
            #         ShoppingPoint.objects.create(
            #             user=buyer_user.referred_by,
            #             transaction_type='credit',
            #             points=referrer_points,
            #             description="Referral reward",
            #             source_user=buyer_user
            #         )

            #         logger.info(f"buyer_user.referred_by - {buyer_user.referred_by.id}")

            #         referrer_user = User.objects.get(id=buyer_user.referred_by.id)

            #         try:
            #             send_referrer_reward_email.delay(referrer_user.id, referrer_points, buyer_user.id)
            #             logger.info(f"Enqueued email task for referrer reward {referrer_user}")
            #         except Exception as e:
            #             logger.exception(f"Failed to enqueue buyer referrer email for referrer ID {buyer_user.id}: {str(e)}")

            #         referrer_user.total_points = (referrer_user.total_points or 0) + referrer_points
            #         referrer_user.save()
            #         logger.info(f'Referrer reward Point - {referrer_user.total_points}')

            #     else:
            #         logger.info(f"Referrer reward already given to {buyer_user.referred_by} for referring {buyer_user}")

            #     referred_point_exists = ShoppingPoint.objects.filter(
            #         user=buyer_user,
            #         source_user=buyer_user.referred_by,
            #         transaction_type='credit'
            #         # description="Welcome reward via referral code"
            #     ).exists()

            #     logger.info(f'referred_point_exists - { referred_point_exists}',)

            #     if not referred_point_exists:
            #         ShoppingPoint.objects.create(
            #             user=buyer_user,
            #             transaction_type='credit',
            #             points=referred_points,
            #             description="Welcome reward via referral code",
            #             source_user=buyer_user.referred_by
            #         )
            #         try:
            #             send_referred_reward_email.delay(buyer_user.id, referred_points)
            #             logger.info(f"Enqueued email task for referred reward {buyer_user.referred_by}")
            #         except Exception as e:
            #             logger.exception(f"Failed to enqueue buyer referred email for referred ID {buyer_user.id}: {str(e)}")

            #         buyer_user.total_points = (buyer_user.total_points or 0) + referred_points
            #         buyer_user.save()
            #         logger.info(f'Referred reward Point - {buyer_user.total_points}')

            #     else:
            #         logger.info(f"Referred user {buyer_user} has already received welcome shopping points.")


            buyer_ser = UserProfileSerializer(buyer_user)
            return Response({'msg': 'OTP verified Successfully', 'data': buyer_ser.data}, status=status.HTTP_200_OK)

        except Exception as e:
            logger.info(f"[OTP Log] - Error verifying OTP: {str(e)}")
            return Response(
                {'msg': 'Something went wrong. Please try again later.', 'error': str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )

        # serializer = self.get_serializer(data = request.data)
        # serializer.is_valid(raise_exception = True)

        # email = serializer.validated_data.get('email')
        # otp = serializer.validated_data.get('otp')

        # buyer_user = User.objects.filter(email = email).first()
        # # buyer_user = User.objects.get(email = email)
   
        # if buyer_user.otp != otp:
        #     return Response({'msg':'Invalid OTP'}, status = status.HTTP_200_OK)
        
        # buyer_user.otp_verified=True
        # buyer_user.is_active=True
        # buyer_user.is_staff = True 
        # buyer_user.save()
        # buyer_ser = UserProfileSerializer(buyer_user)

        # return Response({'msg':'OTP verified Successfully','data':buyer_ser.data}, status = status.HTTP_200_OK)
    


class BuyerPasswordResetRequestViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = VendorPasswordResetRequestSer
    # pagination_class = CustomPagination
    # permission_classes = [AllowAny]

    def create(self, request, *args, **kwargs):
        serializer = self.serializer_class(data = request.data)
        serializer.is_valid(raise_exception=True)

        email = serializer.validated_data.get('email')

        buyer_user = User.objects.filter(email = email).first()

        if buyer_user == None:
            return Response({'msg':'Email not registered. Please sign up.'}, status = status.HTTP_404_NOT_FOUND)

        # Generate OTP
        otp = generate_otp()
        # GenerateOTP.objects.create(buyer_user = buyer_user, otp = otp)

        buyer_user.otp = otp

        buyer_user.save()

        # Send OTP via Email
        body = 'OTP is : '+ otp

        data = {
            'subject':'e360 Mart OTP for buyer password reset',
            'body':body,
            'to_email':email,
            'otp':otp
        }

        send_email_otp(data)

        return Response({'msg':f'OTP sent to registered email.',}, status = status.HTTP_200_OK)



class BuyerPasswordResetOTPVerifyViewSet(viewsets.ViewSet):
    # queryset = AdminUser.objects.all()
    serializer_class = BuyerPasswordResetOTPVerifySer
    # pagination_class = CustomPagination
    # permission_classes = [AllowAny]

    def create(self, request, *args, **kwargs):
        # otp = request.data.pop('otp')
        serializer = self.serializer_class(data = request.data)
        serializer.is_valid(raise_exception=True)

        email = serializer.validated_data.get('email')
        otp = int(serializer.validated_data.get('otp'))

        buyer_user = User.objects.get(email = email)
        # otp_obj = GenerateOTP.objects.filter(buyer_user = buyer_user, otp=otp).first()
        stored_otp = buyer_user.otp
        if stored_otp == otp:   
            # buyer_user.set_password(password)
            # buyer_user.password = password
            buyer_user.otp_verified = True
            buyer_user.save()
            return Response({'msg':f'OTP verified Successfully'}, status = status.HTTP_200_OK)
        else:
            return Response({'msg':'Incorrect OTP'}, status = status.HTTP_400_BAD_REQUEST)


class BuyerPasswordResetViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = BuyerPasswordResetSer
    # pagination_class = CustomPagination

    def create(self, request, *args, **kwargs):
        serializer = self.serializer_class(data = request.data)
        serializer.is_valid(raise_exception=True)

        email = serializer.validated_data.get('email')
        password = serializer.validated_data.get('password')

        buyer_user = User.objects.filter(email = email).first()

        if buyer_user.otp_verified == False:
            return Response({'error':'Invalid OTP'},status=status.HTTP_400_BAD_REQUEST)
        
        buyer_user.set_password(password)
        buyer_user.save()

        return Response({'msg':f'Password Change for Buyer Successfully for email {email}'},status=status.HTTP_200_OK)


class BuyerLoginViewSet(viewsets.ViewSet):
    queryset = User.objects.all()
    serializer_class = BuyerLoginSer 
    # pagination_class = CustomPagination

    def get_serializer_context(self):
        context = super().get_serializer_context()
        context['request'] = self.request
        return context

    def create(self, request, *args, **kwargs):
        try:
            serializer = self.serializer_class(data=request.data)
            serializer.is_valid(raise_exception=True) 

            email = serializer.validated_data.get('email')
            password = serializer.validated_data.get('password')
            print('--------- Request received for login ---------')
            print(f'Email: {email}')

            buyer_user = User.objects.filter(email=email).first()
            print('------ Retrieved User ------', buyer_user)

            if buyer_user is None:
                print('User not found with this email.')
                return Response({'msg': 'Email not registered. Please sign up.'}, status=status.HTTP_404_NOT_FOUND)

            if buyer_user.is_superuser:
                print('Attempted login with superuser account.')
                return Response({
                    "msg": "Admin accounts cannot log in as buyer. Please use a different email that isn't associated with an admin account."
                }, status=status.HTTP_403_FORBIDDEN)
            
            if buyer_user.is_vendor:
                print('Attempted login with superuser account.')
                return Response({
                    "msg": "Vendor accounts cannot log in as buyer. Please use a different email that isn't associated with an vendor account."
                }, status=status.HTTP_403_FORBIDDEN)

            if not check_password(password, buyer_user.password):
                print('Incorrect password provided.')
                return Response({'msg': 'Incorrect password'}, status=status.HTTP_400_BAD_REQUEST)

            if not buyer_user.otp_verified:
                print('OTP is not verified.')
                return Response({'otp_verified': False, 'msg': 'OTP is not verified!'}, status=status.HTTP_400_BAD_REQUEST)

            if not buyer_user.is_active:
                print('Buyer account is deactivated.')
                return Response({'error': 'Buyer account is deactive'}, status=status.HTTP_400_BAD_REQUEST)

            # Optional: staff check if needed
            # if buyer_user.is_staff == '1':
            #     print('Buyer is not approved by admin.')
            #     return Response({'error': 'Buyer is not approved by admin'}, status=status.HTTP_400_BAD_REQUEST)

            token = get_tokens_for_user(buyer_user)
            buyer_ser = BuyerRegisterSer(buyer_user)
            print('Login successful.')

            return Response({'msg': 'Login successful', 'token': token, 'data': buyer_ser.data}, status=status.HTTP_200_OK)

        except Exception as e:
            print('An unexpected error occurred during login:', str(e))
            return Response(
                {'msg': 'Something went wrong during login.', 'error': str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )
        # serializer = self.serializer_class(data=request.data)
        # serializer.is_valid(raise_exception=True) 

        # email = serializer.validated_data.get('email')
        # password = serializer.validated_data.get('password')
        # print('--------//////-----------')
        
        # buyer_user = User.objects.filter(email=email).first()  
        # print('-----buyer_user------', buyer_user)

        # if buyer_user.is_superuser==True:
        #     return Response({"msg":"Admin accounts cannot log in as buyer. Please use a different email that isn't associated with an admin account."},status=status.HTTP_403_FORBIDDEN)
        
        # if buyer_user is None:
        #     return Response({'msg': 'Email not registered. Please sign up.'}, status=status.HTTP_404_NOT_FOUND)
        
        # if not check_password(password, buyer_user.password):
        #     return Response({'msg': 'Incorrect password'}, status=status.HTTP_400_BAD_REQUEST)
        
        # if buyer_user.otp_verified == False:
        #     return Response({'otp_verified':False, 'msg': 'OTP is not verified!'}, status=status.HTTP_400_BAD_REQUEST)
        
        # if buyer_user.is_active==False:  
        #     return Response({'error':'buyer account is deactive'},status=status.HTTP_400_BAD_REQUEST)
        
        # # if buyer_user.is_staff=='1':
        # #     return Response({'error':'buyer is not approved by admin'},status=status.HTTP_400_BAD_REQUEST)
        
        
        # buyer_ser = BuyerRegisterSer(buyer_user)
        # token = get_tokens_for_user(buyer_user)
        # return Response({'msg': 'Login successful', 'token': token, 'data': buyer_ser.data}, status=status.HTTP_200_OK)

class VendorProfile(viewsets.ModelViewSet):
    queryset = User.objects.filter(is_vendor=True)
    serializer_class = VendorProfileSer
    # pagination_class = CustomPagination
    # authentication_classes = [CustomJWTAuthentication]
    @cache_response()
    def list(self, request, *args, **kwargs):
        queryset = self.get_queryset().order_by('-id')
        #page = self.paginate_queryset(queryset)
      #  if page is not None:
          #  serializer = self.get_serializer(page, many=True)
          #  return self.get_paginated_response(serializer.data)
        serializer = self.get_serializer(queryset, many=True) 
        return Response({'msg': 'Vendor profiles fetched successfully', 'data': serializer.data}, status=status.HTTP_200_OK)
    
    
    @cache_response()
    def retrieve(self, request, *args, **kwargs):
        vendor_id = request.user.id   

        vendor_obj = User.objects.filter(id = vendor_id , is_vendor = True).first()

        if vendor_obj == None:
            return Response({'error':'User not exist'},status=status.HTTP_404_NOT_FOUND)

        serializer = self.get_serializer(vendor_obj)

        return Response({'msg':'vendor profile fetched successfully','data':serializer.data}, status = status.HTTP_200_OK)
    
class BuyerProfile(viewsets.ModelViewSet):
    queryset = User.objects.filter(is_buyer=True)
    serializer_class = BuyerRegisterSer
    # pagination_class = CustomPagination
    @cache_response()
    def list(self, request, *args, **kwargs):
        queryset = self.get_queryset().filter(is_buyer=True).order_by('-id')
        #page = self.paginate_queryset(queryset)
      #  if page is not None:
          #  serializer = self.get_serializer(page, many=True)
          #  return self.get_paginated_response(serializer.data)
        serializer = self.get_serializer(queryset, many=True)
        return Response({'msg': 'buyer profiles fetched successfully', 'data': serializer.data}, status=status.HTTP_200_OK)
    @cache_response()
    def retrieve(self, request, pk = None):
        # print("request.__dict__----",request.__dict__)
        user_instance = request.user
        # user_instance = self.get_object()
        # print("user_instance----",user_instance)
        # Favourite Products
        fav_product = user_instance.user_favourite_products.all()
        # print("fav_product----",fav_product)

        product_data = []
        for fav in fav_product:
            try:
                product = fav.product  # This may raise a DoesNotExist exception
                product_data.append(BuyerProductSer(product, context={'request': request}).data)
            except Product.DoesNotExist:
                # Handle the case where the related product does not exist
                continue
        serializer = BuyerRegisterSer(user_instance, context={'request': request})
        return Response({"data":serializer.data,"favourite_products":product_data}, status = status.HTTP_200_OK)

class UserRetrieveViewSet(viewsets.ModelViewSet): 
    queryset = User.objects.all()
    serializer_class = UserProfileSerializer
    # pagination_class = CustomPagination
    # authentication_classes = [CustomJWTAuthentication] 

    def get_serializer_class(self):
        if self.action == 'create':
            return UserCreateSerializer
        return super().get_serializer_class()
    @cache_response()
    def list(self, request, *args, **kwargs):
        queryset = self.get_queryset().order_by('-id')
        #page = self.paginate_queryset(queryset)
      #  if page is not None:
          #  serializer = self.get_serializer(page, many=True)
          #  return self.get_paginated_response(serializer.data)
        serializer = self.get_serializer(queryset, many=True)
        return Response({
            'msg': 'users fetch successfully',
            'data': serializer.data
        }, status=status.HTTP_200_OK)
    @cache_response()
    def retrieve(self, request, *args, **kwargs):
        instance = self.get_object()
        fav_product = instance.user_favourite_products.all()
        fav_product_ids = instance.user_favourite_products.values_list('product__id', flat=True)

        product_data = []
        for fav in fav_product:
            try:
                product = fav.product  # This may raise a DoesNotExist exception
                product_data.append(product.id)
            except Product.DoesNotExist:
                # Handle the case where the related product does not exist
                continue
        serializer = self.get_serializer(instance)
        return Response({
            'msg': 'user fetch successfully',
            'data': serializer.data,
            'favourite_products':fav_product_ids
        }, status=status.HTTP_200_OK) 


class PermissonsRetrieveViewSet(viewsets.ModelViewSet): 
    queryset = Permission.objects.all()  
    serializer_class = PermissionSerializer 
    # pagination_class = CustomPagination


class UserViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = VendorProfileSer
    # pagination_class = CustomPagination
    @cache_response()
    def list(self, request, *args, **kwargs):
        # Override the default list method to list all users (buyers and vendors)
        queryset = self.get_queryset()
        #page = self.paginate_queryset(queryset)
      #  if page is not None:
          #  serializer = self.get_serializer(page, many=True)
          #  return self.get_paginated_response(serializer.data)
        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)
    
    @action(detail=False, methods=['get'])
    @cache_response()
    def list_buyers(self, request):
        buyers = User.objects.filter(is_buyer=True)
        page = self.paginate_queryset(buyers)
        # if page is not None:
        #     serializer = self.get_serializer(page, many=True)
        #     return self.get_paginated_response(serializer.data)
        serializer = self.get_serializer(buyers, many=True)
        return Response(serializer.data)

    @action(detail=False, methods=['get'])
    @cache_response()
    def nearby_vendors_by_buyer(self, request):
        buyer_id = request.query_params.get('buyer_id')
        if not buyer_id:
            return Response({'error': 'Buyer ID is required as query parameter'}, status=status.HTTP_400_BAD_REQUEST)
        
        try:
            buyer = User.objects.get(pk=int(buyer_id), is_buyer=True)  # Convert buyer_id to integer
        except ValueError:
            return Response({'error': 'Buyer ID must be an integer'}, status=status.HTTP_400_BAD_REQUEST)
        except User.DoesNotExist:
            return Response({'error': 'Buyer not found'}, status=status.HTTP_404_NOT_FOUND)

        buyer_location = (buyer.lat, buyer.long)
        vendors = User.objects.filter(is_vendor=True)
        
        nearby_vendors = [
            vendor for vendor in vendors
            if geodesic(buyer_location, (vendor.lat, vendor.long)).km <= 10
        ]

        nearby_vendor_ids = [vendor.id for vendor in nearby_vendors]
        nearby_vendor_products = Product.objects.filter(user_id__in=nearby_vendor_ids)
        serialized_products = ProductSer(nearby_vendor_products, many=True).data

        return Response(serialized_products, status=status.HTTP_200_OK)

class ResendOTPRequestViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = VendorPasswordResetRequestSer
    # pagination_class = CustomPagination
    # permission_classes = [AllowAny]

    def create(self, request, *args, **kwargs):
        serializer = self.serializer_class(data=request.data)
        serializer.is_valid(raise_exception=True)

        email = serializer.validated_data.get('email')

        try:
            # Fetch the user by email
            user = User.objects.filter(email = email).first()

            # Generate OTP
            otp = generate_otp()
            user.otp = otp
            user.save()

            # Send OTP via Email
            body = f'Your OTP is: {otp}'

            data = {
                'subject': 'e360 Mart OTP for verification',
                'body': body,
                'to_email': email,
                'otp':otp
            }

            send_email_otp(data)
            # print(data,"hgfds")
            return Response({'msg': 'OTP resend successfully '}, status=status.HTTP_200_OK)
        except ObjectDoesNotExist:
            return Response({'error': 'User with this email does not exist.'}, status=status.HTTP_404_NOT_FOUND)
        except Exception as e:
            return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
        
class ChangePasswordViewSet(viewsets.ViewSet):
    # queryset = AdminUser.objects.all()
    serializer_class = ChangePasswordSer
    # pagination_class = CustomPagination
    # permission_classes = [AllowAny]

    def create(self, request, *args, **kwargs):
        # otp = request.data.pop('otp')
        serializer = self.serializer_class(data = request.data)
        serializer.is_valid(raise_exception=True)

        email = serializer.validated_data.get('email')
        old_password = serializer.validated_data.get('old_password')
        password = serializer.validated_data.get('password')
        confirm_password = serializer.validated_data.get('confirm_password')

        user = User.objects.filter(email = email).first()
        if not check_password(old_password,user.password):
            return Response({'msg':'The old password you entered is incorrect. Please try again.'},status=status.HTTP_400_BAD_REQUEST)
        else:
            if password!=confirm_password:
                return Response({'msg':'Password and ConfirmPassword should be same. Please try again.'},status=status.HTTP_400_BAD_REQUEST)
            else:
                user.set_password(password)
                user.save()
                return Response({'msg':f'Password Changed Successfully'}, status = status.HTTP_200_OK)
                      
class VendorProduct(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = VendorProfileSer
    # pagination_class = CustomPagination
    # authentication_classes = [CustomJWTAuthentication]
    @cache_response()
    def retrieve(self, request,pk=None):
        # vendor = request.user.id   
        # vendor_obj = User.objects.filter(id = pk , is_vendor = True).first()
        vendor_obj = get_object_or_404(User, id=pk, is_vendor=True)
        
        if vendor_obj == None:
            return Response({'error':'User not exist'},status=status.HTTP_404_NOT_FOUND)
        serializer = self.get_serializer(vendor_obj)
        products = Product.objects.filter(user=vendor_obj)
        product_serializer = ProductSer(products, many=True,context={'request':request})
        products_data = product_serializer.data


        return Response({'msg':'vendor profile fetched successfully','data':serializer.data,'products': product_serializer.data}, status = status.HTTP_200_OK)
    
class VendorProductDetail(viewsets.ViewSet):

    # def list(self, request):
    #     vendors = User.objects.filter(is_vendor=True) 
    #     serializer = VendorProfileSer(vendors, many=True, context={'request': request})
    #     return Response({'msg': 'Vendor list fetched successfully', 'data': serializer.data}, status=status.HTTP_200_OK)

    def retrieve(self, request, pk=None):
      
        vendor_obj = User.objects.filter(id = pk , is_vendor = True).first()

        if vendor_obj == None:
            return Response({'error':'User not exist'},status=status.HTTP_404_NOT_FOUND)

        serializer = VendorProfileSer(vendor_obj, context={'request': request})

        products = Product.objects.filter(user=vendor_obj)
        product_serializer = ProductSer(products, many=True, context={'request': request,'user': request.user})

        return Response(
            {
                'msg':'vendor profile fetched successfully',
                'data':serializer.data,
                'products': product_serializer.data
            }, status = status.HTTP_200_OK)
    
   
    
class UserdelViewSet(viewsets.ModelViewSet):
    queryset = User.objects.filter(is_superuser=False)
    authentication_classes=[CustomJWTAuthentication]
    permission_classes = [IsAuthenticated]

    def create(self, request, *args, **kwargs):
        serializer = UserDeletionSerializer(data=request.data)
        if serializer.is_valid():
            email = serializer.validated_data['email']
            tokenemail=request.user.email
            if email != tokenemail:
                return Response({'error': 'You are not authorized to delete this user'}, status=status.HTTP_403_FORBIDDEN)
            try:
                # Fetch the user
                user = User.objects.get(email=email)

                if user.is_superuser:
                    return Response({'error': 'Superuser accounts cannot be deleted'}, status=status.HTTP_403_FORBIDDEN)

                # Try to delete user
                user.delete()
                return Response({'message': 'User deleted successfully'}, status=status.HTTP_200_OK)

            except User.DoesNotExist:
                return Response({'error': 'User not found'}, status=status.HTTP_404_NOT_FOUND)
            
            except IntegrityError:
                return Response({
                    'error': 'This user cannot be deleted because related records exist in other tables (e.g., orders, transactions).'
                }, status=status.HTTP_400_BAD_REQUEST)
        
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

class RegisterSsoViewSet(viewsets.ModelViewSet):

    queryset = User.objects.all()
    serializer_class = RegisterSerializer
    http_method_names = ['post']  # Restrict to POST only

    def create(self, request, *args, **kwargs):
        try:
            sso_id = request.data.get('sso_id')

            if not sso_id:
                print("[Google Log] - SSO ID not provided in request.")
                return Response(
                    {'msg': 'SSO ID is required'},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # Check if a user with the given SSO ID exists
            user = User.objects.filter(sso_id=sso_id).first()

            if user:
                # Login logic
                user_data = BuyerRegisterSer(user).data
                token = get_tokens_for_user(user)
                print(f"[Google Log] - User login successful for SSO ID: {sso_id}")
                return Response(
                    {'msg': 'Login successful', 'token': token, 'data': user_data},
                    status=status.HTTP_200_OK
                )
            else:
                # Registration logic
                email = request.data.get('email')
                user_check = User.objects.filter(email=email).first()

                if user_check:
                    print(f"[Google Log] - User Already register: {email}")
                    return Response(
                        {"msg": "Your account already exists. Please login with email and password"},
                        status=status.HTTP_400_BAD_REQUEST
                    )
                
                invited_by_code = request.data.get('invited_by_code')

                if invited_by_code:
                    referral_user = User.objects.filter(
                        is_buyer=True,
                        referral_code=invited_by_code,
                        # otp_verified=True
                    ).first()

                    if not referral_user or (not referral_user.sso_id and not referral_user.otp_verified):
                        return Response(
                            {
                                "status" : False,
                                "error": {
                                    "referral_code": "Invalid referral code or user not verified."
                                }
                            },
                            status=status.HTTP_400_BAD_REQUEST
                        )
                    # Copy request data to make it mutable and inject `referred_by` ID
                    data = request.data.copy()
                    data['referred_by'] = referral_user.id
                else:
                    data = request.data
                
                data['referral_code'] = generate_unique_referral_code()
                data['otp_verified'] = True

                # Now pass the (possibly modified) data to serializer
                serializer = self.get_serializer(data=data)

                # serializer = self.get_serializer(data=request.data)
                if serializer.is_valid():
                    user = serializer.save()

                    # if user.referred_by:

                    #     referrer_points = int(get_setting_value('referrer_reward_points'))
                    #     referred_points = int(get_setting_value('referred_user_reward_points'))

                    #     logger.info(f"Referrer - {user.referred_by}")

                    #     referrer_point_exists = ShoppingPoint.objects.filter(
                    #         user=user.referred_by,
                    #         source_user=user,
                    #         transaction_type='credit'
                    #         # description="Referral reward"
                    #     ).exists()

                    #     logger.info(f"referrer_point_exists - {referrer_point_exists}")

                    #     if not referrer_point_exists:
                    #         ShoppingPoint.objects.create(
                    #             user=user.referred_by,
                    #             transaction_type='credit',
                    #             points=referrer_points,
                    #             description="Referral reward",
                    #             source_user=user
                    #         )

                    #         logger.info(f"user.referred_by - {user.referred_by.id}")

                    #         referrer_user = User.objects.get(id=user.referred_by.id)

                    #         try:
                    #             send_referrer_reward_email.delay(referrer_user.id, referrer_points, user.id)
                    #             logger.info(f"Enqueued email task for referrer reward {referrer_user}")
                    #         except Exception as e:
                    #             logger.exception(f"Failed to enqueue buyer referrer email for referrer ID {user.id}: {str(e)}")

                    #         referrer_user.total_points = (referrer_user.total_points or 0) + referrer_points
                    #         referrer_user.save()
                    #         logger.info(f'Referrer reward Point - {referrer_user.total_points}')

                    #     else:
                    #         logger.info(f"Referrer reward already given to {user.referred_by} for referring {user}")

                    #     referred_point_exists = ShoppingPoint.objects.filter(
                    #         user=user,
                    #         source_user=user.referred_by,
                    #         transaction_type='credit'
                    #         # description="Welcome reward via referral code"
                    #     ).exists()

                    #     logger.info(f'referred_point_exists - { referred_point_exists}',)

                    #     if not referred_point_exists:
                    #         ShoppingPoint.objects.create(
                    #             user=user,
                    #             transaction_type='credit',
                    #             points=referred_points,
                    #             description="Welcome reward via referral code",
                    #             source_user=user.referred_by
                    #         )
                    #         try:
                    #             send_referred_reward_email.delay(user.id, referred_points)
                    #             logger.info(f"Enqueued email task for referred reward {user.email}")
                    #         except Exception as e:
                    #             logger.exception(f"Failed to enqueue buyer referred email for referred ID {user.id}: {str(e)}")

                    #         user.total_points = (user.total_points or 0) + referred_points
                    #         user.save()
                    #         logger.info(f'Referred reward Point - {user.total_points}')

                    #     else:
                    #         logger.info(f"Referred user {user} has already received welcome shopping points.")


                    token = get_tokens_for_user(user)
                    user_data = RegisterSerializer(user).data
                    user = User.objects.filter(sso_id=sso_id).first()
                    user_data = BuyerRegisterSer(user).data

                    print(f"[Google Log] - User registered successfully for SSO ID: {sso_id}")
                    return Response(
                        {'msg': 'User registered successfully', 'token': token, 'data': user_data},
                        status=status.HTTP_201_CREATED
                    )
                errors = {field: error[0] for field, error in serializer.errors.items()}
                print(f"[Google Log] - Validation error during registration: {errors}")
                return Response(
                    {'msg': 'Validation error', 'errors': errors},
                    status=status.HTTP_400_BAD_REQUEST
                )
        except Exception as e:
            print(f"[Google Log] - Unexpected error in user create API: {str(e)}")
            return Response(
                {'msg': 'Something went wrong. Please try again later.', 'error': str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )
