from django.shortcuts import render, get_object_or_404
from rest_framework import generics, permissions
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework import status
from order.models import *
from product.models import *
from ..serializers import *
from django.db import transaction
from suscription.custom_pagination import CustomPagination
from Help_Support.decorators import cache_response
from rest_framework.exceptions import ValidationError
from setting.views import *
from decimal import Decimal
from rest_framework.views import APIView
from rest_framework import viewsets
from rest_framework.generics import UpdateAPIView
from rest_framework.decorators import action
from django.db.models import Q
from rest_framework.permissions import AllowAny
from datetime import datetime, timedelta, time
from django.db.models import Sum
import requests
import random
from vendor_listing.tasks import send_vendor_payout_email
from login_signup.utils import * 
import logging
import uuid
from notification.tasks import create_user_notification

logger = logging.getLogger(__name__)


class VendorWalletCreditView(generics.ListAPIView):
    permission_classes = [IsAuthenticated]
    serializer_class = VendorCreditListingSerializers
    pagination_class = CustomPagination

    def get_queryset(self):
        vendor = self.request.user
        queryset = WalletTransaction.objects.filter(
            vendor=vendor,
            transaction_type='credit'
        ).select_related("vendor").order_by("-created_at")


        start_date = self.request.query_params.get('start_date')
        end_date = self.request.query_params.get('end_date')
        # if start_date and end_date:
        #     end_date_obj = datetime.strptime(end_date, "%Y-%m-%d") + timedelta(days=1)
        #     queryset = queryset.filter(created_at__range=[start_date, end_date_obj])
        # elif start_date:
        #     queryset = queryset.filter(created_at__gte=start_date)
        # elif end_date:
        #     end_date_obj = datetime.strptime(end_date, "%Y-%m-%d") + timedelta(days=1)
        #     queryset = queryset.filter(created_at__lt=end_date_obj)

        if start_date and end_date:
            start_date_obj = datetime.strptime(start_date, "%Y-%m-%d")
            end_date_obj = datetime.combine(datetime.strptime(end_date, "%Y-%m-%d"), time.max)
            queryset = queryset.filter(
                Q(created_at__range=[start_date_obj, end_date_obj]) |
                Q(credited_date__range=[start_date_obj, end_date_obj])
            )
        elif start_date:
            start_date_obj = datetime.strptime(start_date, "%Y-%m-%d")
            queryset = queryset.filter(
                Q(created_at__gte=start_date_obj) |
                Q(credited_date__gte=start_date_obj)
            )
        elif end_date:
            end_date_obj = datetime.combine(datetime.strptime(end_date, "%Y-%m-%d"), time.max)
            queryset = queryset.filter(
                Q(created_at__lte=end_date_obj) |
                Q(credited_date__lte=end_date_obj)
            )
     

        search_query = self.request.query_params.get('search')
        if search_query:
            queryset = queryset.filter(
                Q(amount__icontains=search_query) |
                Q(status__icontains=search_query) |
                Q(order_purchase__transactions__id__icontains=search_query) |
                Q(created_at__icontains=search_query)
            )

        return queryset

    def list(self, request, *args, **kwargs):
        queryset = self.get_queryset()

        # wallet_balance = WalletTransaction.objects.filter(vendor=self.request.user, transaction_type='credit', status='completed', is_withdraw=False).aggregate(total=models.Sum('amount'))['total'] or 0

        page = self.paginate_queryset(queryset)  
        if page is not None:
            serializer = self.get_serializer(page, many=True, context={'request': request})
            paginated_response = self.get_paginated_response(serializer.data)  
            
            return Response({
                "status": True,
                "message": "Wallet transactions fetched successfully",
                "data": paginated_response.data 
            })

        serializer = self.get_serializer(queryset, many=True, context={'request': request})
        return Response({
            "status": True,
            "message": "Wallet transactions fetched successfully",
            "data": serializer.data
        })
    

class WalletBankDetailAPIView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request, *args, **kwargs):
        vendor = request.user

        # # Calculate wallet balance: Sum all transactions (credits as positive, debits as negative)
        # wallet_balance = WalletTransaction.objects.filter(vendor=vendor).aggregate(
        #     balance=Sum('amount')
        # )['balance'] or 0

        # wallet_balance = WalletTransaction.objects.filter(vendor=self.request.user, transaction_type='credit', status='completed', is_withdraw=False).aggregate(total=models.Sum('vendor_total_amount'))['total'] or 0


        wallet_balance = WalletBalance.objects.filter(
            vendor=vendor
        ).values_list('balance', flat=True).first() or Decimal('0.00')


        # wallet_balance = WalletTransaction.objects.filter(vendor=self.request.user, transaction_type='credit', status='completed', is_withdraw=False).aggregate(total=models.Sum('amount'))['total'] or 0

        # Get bank details for the vendor. 
        bank_details = VendorBankDetail.objects.filter(vendor=vendor)
        bank_serializer = VendorBankDetailSerializer(bank_details, many=True)

        data = {
            "wallet_balance": wallet_balance,
            "bank_details": bank_serializer.data
        }

        return Response({
            "status": True,
            "message": "Wallet balance and bank details retrieved successfully",
            "data": data
        }, status=status.HTTP_200_OK)
    
def verify_bank_account(account_number, bank_code):
    
    url = "https://api.flutterwave.com/v3/accounts/resolve"
    headers = {
        "Authorization": f"Bearer {settings.FLUTTERWAVE_SECRET_KEY}",
        "Content-Type": "application/json"
    }

    payload = {
        "account_number": account_number,
        "account_bank": bank_code
    }
    response = requests.post(url, json=payload, headers=headers)
    return response.json()


def verify_mobile_money(user, mobile_number):
    payload = {
        "tx_ref": f"MM-{uuid.uuid4()}",
        "amount": "1",
        "currency": "TZS",
        "payment_type": "mobilemoneytz",
        # "redirect_url": "https://yourdomain.com/payment-complete",
        "email": user.email,
        "phone_number": mobile_number,
        "fullname": user.full_name
    }

    logger.info('Mobile number verification payload: %s', payload)
    

    headers = {
        "Authorization": f"Bearer {settings.FLUTTERWAVE_SECRET_KEY}"
    }

    response = requests.post("https://api.flutterwave.com/v3/charges?type=mobile_money",
                             json=payload, headers=headers)
    
    return response.json()



    
class VendorBankViewSet(viewsets.ModelViewSet) :

    permission_classes = [IsAuthenticated]
    serializer_class = VendorBankSerializer

    def get_queryset(self):
        return VendorBankDetail.objects.filter(vendor=self.request.user).first()
    
    def list(self, request, *args, **kwargs):
        instance = self.get_queryset()
        if not instance:
            return Response(
                {"status": False, "message": "No bank account found.", "data": None},
                status=status.HTTP_404_NOT_FOUND
            )

        serializer = self.get_serializer(instance)
        return Response(
            {"status": "success", "message": "Bank account retrieved.", "data": serializer.data},
            status=status.HTTP_200_OK
        )
    
    # def create(self, request, *args, **kwargs):

    #     vendor = request.user.id

    #     vendor_detail = VendorBankDetail.objects.filter(vendor=vendor).exists()

    #     # if VendorBankDetail.objects.filter(vendor=vendor).exists():
    #     #     return Response(
    #     #         {"status": False, "message": "You already have an bank account.", "data": None},
    #     #         status=status.HTTP_400_BAD_REQUEST
    #     #     )

    #     payout_method = request.data.get('payout_method', None)

    #     if not payout_method :
    #         return Response({"status": False, "error": "Missing payout method"}, status=400)

    #     if payout_method == 'bank_account' :
    #         account_number = request.data.get('bank_account_number')
    #         bank_code = request.data.get('bank_code')
    #         verification_result = verify_bank_account(account_number, bank_code)
    #     else :
    #         mobile_account_number = request.data.get('mobile_account_number')
    #         mobile_account_bank = request.data.get('mobile_account_bank')
    #         verification_result = verify_mobile_money(request.user, mobile_account_number)


    #     verification_response = Response(verification_result)
    #     verification_result['status'] = "success"
    #     print('----verification_response------', verification_result)

    #     if verification_result.get("status") == "success":

    #         if payout_method == 'mobile_money':

    #             transaction_data = verification_result.get("data", {})
    #             logger.info('Transaction data of charge API for checking Mobile money details: %s', transaction_data)

    #             transaction_id = transaction_data.get("id") if transaction_data else None

    #             if transaction_id:
    #                 headers = {
    #                     "Authorization": f"Bearer {settings.FLUTTERWAVE_SECRET_KEY}"
    #                 }

    #                 refund_resp = requests.post(
    #                     f"https://api.flutterwave.com/v3/transactions/{transaction_id}/refund",
    #                     headers=headers
    #                 )

    #                 try:
    #                     refund_json = refund_resp.json()
    #                 except ValueError:
    #                     refund_json = {"status": "error", "message": "Invalid JSON in refund response"}

    #                 # Log the outcome of the refund
    #                 if refund_json.get("status") == "success":
    #                     logger.info(f"✅ Refund successful for transaction ID {transaction_id}")
    #                 else:
    #                     logger.info(f"❌ Refund failed for transaction ID {transaction_id}")
    #                     logger.info("Reason:", refund_json.get("message", "No error message provided"))

    #             else:
    #                 logger.info("❌ Transaction ID not found in verification result")


    #         # data = request.POST.copy() 
    #         # data = data.dict()  
    #         data = request.data.copy()

    #         data['vendor'] = vendor
    #         serializer = self.get_serializer(data=data)

    #         if serializer.is_valid():
    #             serializer.save(vendor=request.user)
    #             return Response(
    #                 {"status": "success", "message": "Bank account added successfully.", "data": serializer.data},
    #                 status=status.HTTP_201_CREATED
    #             )
    #         return Response(
    #             {"status": "error", "message": "Bank account not created.", "errors": serializer.errors},
    #             status=status.HTTP_400_BAD_REQUEST
    #         )
        
    #     else :
    #         message = verification_result.get("message") or "Please enter valid bank details"
    #         return Response(
    #             {
    #                 "status": False,
    #                 "message": message,
    #                 "data": None
    #             },
    #             status=status.HTTP_400_BAD_REQUEST
    #         )


    def create(self, request, *args, **kwargs):
        vendor = request.user

        payout_method = request.data.get('payout_method')
        if not payout_method:
            return Response({"status": False, "error": "Missing payout method"}, status=400)

        # Prevent duplicate payout method for the same vendor
        # if VendorBankDetail.objects.filter(vendor=vendor, payout_method=payout_method).exists():
        #     return Response(
        #         {"status": False, "message": f"You have already added a {payout_method.replace('_', ' ')}."},
        #         status=status.HTTP_400_BAD_REQUEST
        #     )

        existing_entry = VendorBankDetail.objects.filter(vendor=vendor).first()

        print('-----payout_method-----', payout_method)
        print('-----payout_method//-----', VendorBankDetail.PayoutMethod.MOBILE_MONEY)
        # Verification step
        if payout_method == VendorBankDetail.PayoutMethod.BANK_ACCOUNT:
            account_number = request.data.get('bank_account_number')
            bank_code = request.data.get('bank_code')
            verification_result = verify_bank_account(account_number, bank_code)

            if verification_result.get("status") != "success":
                message = verification_result.get("message") or "Verification failed"
                return Response(
                    {"status": False, "message": message, "data": None},
                    status=status.HTTP_400_BAD_REQUEST
                )

        elif payout_method == VendorBankDetail.PayoutMethod.MOBILE_MONEY:
            mobile_account_number = request.data.get('mobile_account_number')
            mobile_account_bank = request.data.get('mobile_account_bank')
            # verification_result = verify_mobile_money(vendor, mobile_account_number)
        else:
            return Response(
                {"status": False, "message": "Invalid payout method."},
                status=status.HTTP_400_BAD_REQUEST
            )

     

        # Optional refund step for mobile money verification
        # if payout_method == VendorBankDetail.PayoutMethod.MOBILE_MONEY:
        #     transaction_id = verification_result.get("data", {}).get("id")
        #     if transaction_id:
        #         headers = {
        #             "Authorization": f"Bearer {settings.FLUTTERWAVE_SECRET_KEY}"
        #         }
        #         refund_resp = requests.post(
        #             f"https://api.flutterwave.com/v3/transactions/{transaction_id}/refund",
        #             headers=headers
        #         )
        #         try:
        #             refund_json = refund_resp.json()
        #         except ValueError:
        #             refund_json = {"status": "error", "message": "Invalid JSON in refund response"}

        #         if refund_json.get("status") == "success":
        #             logger.info(f"✅ Refund successful for transaction ID {transaction_id}")
        #         else:
        #             logger.warning(f"❌ Refund failed for transaction ID {transaction_id}: {refund_json.get('message')}")

        # Create the record
        data = request.data.copy()
        data['vendor'] = vendor.id

        # serializer = self.get_serializer(data=data)

        if existing_entry:
            # Only update relevant fields
            serializer = self.get_serializer(existing_entry, data=data, partial=True)
        else:
            serializer = self.get_serializer(data=data)

        if serializer.is_valid():
            serializer.save(vendor=vendor)
            return Response(
                {"status": "success", "message": "Payout method added successfully.", "data": serializer.data},
                status=status.HTTP_201_CREATED
            )

        return Response(
            {"status": "error", "message": "Validation failed.", "errors": serializer.errors},
            status=status.HTTP_400_BAD_REQUEST
        )
    
    def update(self, request, *args, **kwargs):

        vendor_bank = VendorBankDetail.objects.filter(id=kwargs.get('pk'), vendor=request.user).first()
        if not vendor_bank:
            return Response(
                {"status": False, "message": "Bank account not found.", "data": None},
                status=status.HTTP_404_NOT_FOUND
            )
        
        account_number = request.data.get('bank_account_number')
        bank_code = request.data.get('bank_code')
    
        if account_number and bank_code:
            verification_result = verify_bank_account(account_number, bank_code)
            if verification_result.get("status") != "success":
                return Response(
                    {"status": False, "message": "Please enter valid bank details", "data": None},
                    status=status.HTTP_400_BAD_REQUEST
                )

        data = request.data.copy()
        data['vendor'] = request.user.id

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

        if serializer.is_valid():
            serializer.save()
            return Response(
                {"status": "success", "message": "Bank details updated successfully.", "data": serializer.data},
                status=status.HTTP_200_OK
            )
        return Response(
            {"status": "error", "message": "Bank update failed.", "errors": serializer.errors},
            status=status.HTTP_400_BAD_REQUEST
        )

def generate_unique_id():
    return str(random.randint(10**11, (10**12) - 1))  # 12-digit random number as string


class VendorPayoutView(viewsets.ModelViewSet):
   
    permission_classes = [IsAuthenticated]
    serializer_class = VendorPayoutSerializer
    # queryset = PayoutRequest.objects.all()

    def get_queryset(self):
        queryset = PayoutRequest.objects.filter(vendor=self.request.user).order_by('-requested_date')

        start_date = self.request.query_params.get('start_date')
        end_date = self.request.query_params.get('end_date')
        if start_date and end_date:
            start_date_obj = datetime.strptime(start_date, "%Y-%m-%d")
            end_date_obj = datetime.combine(datetime.strptime(end_date, "%Y-%m-%d"), time.max)
            queryset = queryset.filter(created_at__range=[start_date_obj, end_date_obj])
        elif start_date:
            start_date_obj = datetime.strptime(start_date, "%Y-%m-%d")
            queryset = queryset.filter(created_at__gte=start_date_obj)
        elif end_date:
            end_date_obj = datetime.combine(datetime.strptime(end_date, "%Y-%m-%d"), time.max)
            queryset = queryset.filter(created_at__lte=end_date_obj)
     

        search_query = self.request.query_params.get('search')
        if search_query:
            queryset = queryset.filter(
                Q(amount__icontains=search_query) |
                Q(status__icontains=search_query) |
                Q(transaction_id=search_query) 
            )

        return queryset

    def list(self, request, *args, **kwargs):
        queryset = self.get_queryset()

        page = self.paginate_queryset(queryset)  
        if page is not None:
            serializer = self.get_serializer(page, many=True, context={'request': request})
            paginated_response = self.get_paginated_response(serializer.data)  
            
            return Response({
                "status": True,
                "message": "Payout requests fetched successfull",
                "data": paginated_response.data 
            }, status=status.HTTP_200_OK)

        serializer = self.get_serializer(queryset, many=True, context={'request': request})
        return Response({
            "status": True,
            "message": "Payout requests fetched successfull",
            "data": serializer.data
        }, status=status.HTTP_200_OK)


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

        data = request.data.copy()  
        
        otp =   data.pop('otp') if data.get('otp') else None
        if not otp :
            return Response({
                "status": False,
                "message": "Pleass pass otp for verify withdraw request",
                "data": None
            }, status.HTTP_404_NOT_FOUND)
        
        if otp == request.user.withdraw_otp :

            if request.user.withdraw_otp_at and now() - request.user.withdraw_otp_at <= timedelta(minutes=5):
                pass 
            else:
                return Response({
                    "status": False,
                    "message": "OTP has expired. Please request a new one.",
                    "data": None
                }, status=status.HTTP_400_BAD_REQUEST)

        else :
            return Response({
                "status": False,
                "message": "The OTP you entered is incorrect. Please try again.",
                "data": None
            }, status.HTTP_404_NOT_FOUND)
        
        bank = VendorBankDetail.objects.filter(vendor=request.user).first()  

        if bank is None:
            
            return Response({
                "status": False,
                "message": "Bank account not found. Please add a bank account to complete the payout.",
                "data": None
            }, status.HTTP_404_NOT_FOUND)

        data['bank'] = bank.id if bank else None  
        if bank.payout_method :
            logger.info('payout method----:%s', bank.payout_method)
            data['payment_method'] = bank.payout_method

        amount = request.data.get('amount')

        if amount is None or float(amount) < 5000:
            return Response({
                "status": False,
                "message": "Withdrawal amount must be greater than or equal to 5000.",
                "data": None
            }, status=status.HTTP_400_BAD_REQUEST)

        # wallet_ids = list(
        #     WalletTransaction.objects.filter(
        #         vendor=self.request.user,
        #         transaction_type='credit',
        #         status='completed',
        #         is_withdraw=False
        #     ).values_list('id', flat=True)
        # )

        # data['wallet_ids'] = wallet_ids

        logger.info('payout Data----:%s', data)


        serializer = self.get_serializer(data=data) 
        serializer.is_valid(raise_exception=True)
        
        user = request.user
        payout_amount = serializer.validated_data['amount']
        
         # Generate 12-digit unique ID
        unique_id = generate_unique_id()
        while PayoutRequest.objects.filter(unique_id=unique_id).exists():
            unique_id = generate_unique_id() 

       
        payout_request = serializer.save(vendor=user, status='pending', unique_id=unique_id)

        # WalletTransaction.objects.filter(vendor=user, transaction_type='credit', status='completed').update(is_withdraw=True)

        current_balance = WalletBalance.objects.filter(
            vendor=user
        ).values_list('balance', flat=True).first() or Decimal('0.00')

        minus_amount = amount or Decimal('0.00')
        new_balance = current_balance - minus_amount

        logger.info(f"[Wallet Update] Vendor ID: {user.id}")
        logger.info(f"Current Balance: {current_balance}")
        logger.info(f"Minus Amount: {minus_amount}")
        logger.info(f"New Balance: {new_balance}")


        WalletBalance.objects.update_or_create(
            vendor=user,
            defaults={'balance': new_balance}
        )


        # try:
        #     send_vendor_payout_email.delay(user.id, amount)
        # except Exception as e:
        #     print(f"Failed to send payout email to admin (Celery task): {str(e)}")

        try:
            send_vendor_payout_email.delay(user.id, amount)
            logger.info(f"✅ Payout email task queued for vendor ID {user.id}, Amount: TZS {amount}")
        except Exception as e:
            logger.error(f"❌ Failed to queue payout email task for vendor ID {user.id}: {str(e)}")

        try:
            message_text = (
                f"Your payout request for TZS {amount} has been received. "
                f"We’ll notify you once it’s processed. Thank you for being a valued partner!"
            )

            create_user_notification.delay(
                user_type='vendor',
                user_id=user.id,
                title="Payout Request Submitted",
                message=message_text
            )
            logger.info(f"✅ Notification task queued for vendor ID {user.id}, Amount: TZS {amount}")
        except Exception as e:
            logger.error(f"❌ Failed to queue vendor notification for vendor ID {user.id}, Amount: TZS {amount}: {str(e)}")
        

        response_data = {
            "status": True,
            "message": "Payout request generated successfully",
            "data": VendorPayoutSerializer(payout_request).data
        }

        return Response(response_data, status=status.HTTP_201_CREATED)


class VendorWithdrawOtp(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request):
        vendor = request.user
        if not vendor.is_vendor:
            logger.warning(f"Unauthorized OTP request attempt by non-vendor user {vendor.email}")
            return Response(
                {"status": False, "error": "Only vendors can request a withdrawal OTP."},
                status=status.HTTP_400_BAD_REQUEST
            )

        try:
            otp = generate_otp(6)

            vendor.withdraw_otp = otp
            vendor.withdraw_otp_at = now()
            vendor.save()

            if vendor.email:
                # send_withdraw_otp_email.delay(vendor.email, otp)
                send_withdraw_otp_email(vendor.email, otp)
                logger.info(f"Withdrawal OTP email task successfully for vendor {vendor.email}")
            else:
                logger.warning(f"Vendor {vendor.id} has no email associated. Cannot send OTP.")

        except Exception as e:
            logger.exception(f"Failed to process withdrawal OTP for vendor {vendor.email}: {str(e)}")
            return Response(
                {"status": False, "error": "Something went wrong while sending the OTP. Please try again."},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )

        return Response(
            {"status": True, "message": "A One-Time Password (OTP) has been sent to your registered email address."},
            status=status.HTTP_200_OK
        )
