from django.shortcuts import render, get_object_or_404, redirect
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import ListView
from django.http import JsonResponse, HttpResponse
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_http_methods
from django.contrib import messages
from django.core.paginator import Paginator
from django.db.models import Q, Sum
from django.db import models
from django.utils import timezone
from .models import Payment, UnreconciledPayment
from customers.models import Customer
from billing.models import Invoice
import json
import logging
from accounts.permissions import (
    has_financial_access,
    EmployeeRequiredMixin,
    CustomerRequiredMixin,
    has_permission,
    get_user_permissions
)

logger = logging.getLogger(__name__)


class PaymentListView(LoginRequiredMixin, ListView):
    model = Payment
    template_name = 'payments/payment_list.html'
    context_object_name = 'payments'
    paginate_by = 20

    def get_queryset(self):
        queryset = Payment.objects.select_related('customer').prefetch_related('invoice').order_by('-created_at')

        # Add search functionality
        search_query = self.request.GET.get('search')
        if search_query:
            queryset = queryset.filter(
                Q(payment_id__icontains=search_query) |
                Q(customer__first_name__icontains=search_query) |
                Q(customer__last_name__icontains=search_query) |
                Q(mpesa_receipt_number__icontains=search_query)
            )

        # Add status filter
        status_filter = self.request.GET.get('status')
        if status_filter:
            queryset = queryset.filter(status=status_filter)

        return queryset

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['search_query'] = self.request.GET.get('search', '')
        context['status_filter'] = self.request.GET.get('status', '')
        context['status_choices'] = Payment.STATUS_CHOICES

        # Add summary stats
        queryset = self.get_queryset()
        context['total_payments'] = queryset.count()
        context['total_amount'] = queryset.aggregate(
            total=models.Sum('amount')
        )['total'] or 0

        return context


@login_required
def create_payment(request):
    """Create a new payment record"""
    if not has_permission(request, 'create_payment'):
        messages.error(request, "You do not have permission to create payments.")
        return redirect('payments:payment_list')

    if request.method == 'POST':
        # Handle payment creation logic here
        messages.success(request, 'Payment created successfully.')
        return redirect('payments:payment_list')

    customers = Customer.objects.all()
    invoices = Invoice.objects.filter(status='sent')

    context = {
        'customers': customers,
        'invoices': invoices,
    }
    return render(request, 'payments/payment_form.html', context)


@login_required
def record_cash_payment(request):
    """Record a cash payment"""
    if not has_permission(request, 'record_cash_payment'):
        messages.error(request, "You do not have permission to record cash payments.")
        return redirect('payments:payment_list')

    if request.method == 'POST':
        # Handle cash payment recording logic here
        messages.success(request, 'Cash payment recorded successfully.')
        return redirect('payments:payment_list')

    customers = Customer.objects.all()
    invoices = Invoice.objects.filter(status='sent')

    context = {
        'customers': customers,
        'invoices': invoices,
        'payment_type': 'cash',
    }
    return render(request, 'payments/payment_form.html', context)


@login_required
def customer_stk_push(request):
    """Initiate M-Pesa STK Push for customer"""
    if not has_permission(request, 'initiate_stk_push'):
        return JsonResponse({'success': False, 'message': 'You do not have permission to initiate STK push.'})

    if request.method == 'POST':
        try:
            import json
            data = json.loads(request.body)

            customer_id = data.get('customer_id')
            phone_number = data.get('phone_number', '').strip()
            amount = data.get('amount', '').strip()
            description = data.get('description', 'Account Top-up')

            if not customer_id or not phone_number or not amount:
                return JsonResponse({
                    'success': False,
                    'message': 'Missing required fields: customer_id, phone_number, or amount'
                })

            # Validate customer exists
            try:
                from customers.models import Customer
                customer = Customer.objects.get(id=customer_id)
            except Customer.DoesNotExist:
                return JsonResponse({
                    'success': False,
                    'message': 'Customer not found'
                })

            # Validate amount
            try:
                amount_float = float(amount)
                if amount_float < 1 or amount_float > 70000:
                    return JsonResponse({
                        'success': False,
                        'message': 'Amount must be between KES 1 and KES 70,000'
                    })
            except ValueError:
                return JsonResponse({
                    'success': False,
                    'message': 'Invalid amount format'
                })

            # Use the M-Pesa service
            from payments.services import MpesaService
            mpesa_service = MpesaService()

            # Initiate STK push
            response = mpesa_service.stk_push(
                phone_number=phone_number,
                amount=int(amount_float),
                account_reference=customer.customer_id,
                transaction_desc=description
            )

            if response.get('ResponseCode') == '0':
                # Store STK transaction record for callback matching
                from payments.models import MpesaTransaction
                MpesaTransaction.objects.create(
                    checkout_request_id=response.get('CheckoutRequestID'),
                    merchant_request_id=response.get('MerchantRequestID', ''),
                    amount=amount_float,
                    phone_number=phone_number,
                    account_reference=customer.customer_id,
                    transaction_desc=description
                )

                return JsonResponse({
                    'success': True,
                    'message': 'STK Push sent successfully! Customer should receive M-Pesa prompt on their phone.',
                    'checkout_request_id': response.get('CheckoutRequestID')
                })
            else:
                error_message = response.get('errorMessage', response.get('ResponseDescription', 'Unknown error'))
                return JsonResponse({
                    'success': False,
                    'message': f'Failed to send STK Push. Error: {error_message}'
                })

        except json.JSONDecodeError:
            return JsonResponse({
                'success': False,
                'message': 'Invalid JSON data'
            })
        except Exception as e:
            logger.error(f"STK Push error: {str(e)}")
            return JsonResponse({
                'success': False,
                'message': f'Error processing STK Push: {str(e)}'
            })

    return JsonResponse({'success': False, 'message': 'Invalid request method'})


@login_required
def mpesa_stk_push(request):
    """Initiate M-Pesa STK Push"""
    if not has_permission(request, 'initiate_stk_push'):
        return JsonResponse({'status': 'error', 'message': 'You do not have permission to initiate STK push.'})

    if request.method == 'POST':
        # Handle M-Pesa STK push logic here
        return JsonResponse({'status': 'success', 'message': 'STK Push initiated'})

    return JsonResponse({'status': 'error', 'message': 'Invalid request method'})


@login_required
def check_mpesa_balance(request):
    """Check M-Pesa account balance"""
    if not has_permission(request, 'check_mpesa_balance'):
        return JsonResponse({'status': 'error', 'message': 'You do not have permission to check M-Pesa balance.'})
    # Handle balance check logic here
    return JsonResponse({'status': 'success', 'balance': '0.00'})


@login_required
def get_mpesa_balance_history(request):
    """Get M-Pesa balance history"""
    if not has_permission(request, 'view_mpesa_balance_history'):
        return JsonResponse({'status': 'error', 'message': 'You do not have permission to view M-Pesa balance history.'})
    # Handle balance history logic here
    return JsonResponse({'status': 'success', 'history': []})


@login_required
def unreconciled_payments_list(request):
    """List unreconciled payments"""
    if not has_permission(request, 'view_unreconciled_payments'):
        messages.error(request, "You do not have permission to view unreconciled payments.")
        return redirect('dashboard:home') # Or another appropriate redirect

    unreconciled_payments = UnreconciledPayment.objects.filter(status='pending').order_by('-transaction_time')

    # Add search functionality
    search_query = request.GET.get('search')
    if search_query:
        unreconciled_payments = unreconciled_payments.filter(
            Q(transaction_id__icontains=search_query) |
            Q(phone_number__icontains=search_query) |
            Q(account_reference__icontains=search_query) |
            Q(first_name__icontains=search_query) |
            Q(last_name__icontains=search_query)
        )

    # Add status filter
    status_filter = request.GET.get('status')
    if status_filter:
        unreconciled_payments = unreconciled_payments.filter(status=status_filter)

    # Paginate results
    paginator = Paginator(unreconciled_payments, 20)
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)

    context = {
        'unreconciled_payments': page_obj,
        'search_query': search_query,
        'status_filter': status_filter,
        'status_choices': UnreconciledPayment.STATUS_CHOICES,
    }
    return render(request, 'payments/unreconciled_payments.html', context)


@login_required
def resolve_unreconciled_payment(request, payment_id):
    """Resolve an unreconciled payment"""
    if not has_permission(request, 'resolve_unreconciled_payment'):
        messages.error(request, "You do not have permission to resolve unreconciled payments.")
        return redirect('payments:unreconciled_payments_list')

    payment = get_object_or_404(UnreconciledPayment, id=payment_id)

    if request.method == 'POST':
        # Handle resolution logic here
        payment.status = 'resolved'
        payment.resolved_by = request.user
        payment.resolved_at = timezone.now()
        payment.save()

        messages.success(request, 'Payment resolved successfully.')
        return redirect('payments:unreconciled_payments_list')

    # Get potential matching customers
    potential_customers = Customer.objects.filter(
        Q(phone_number=payment.phone_number) |
        Q(first_name__icontains=payment.first_name) |
        Q(last_name__icontains=payment.last_name)
    )

    context = {
        'payment': payment,
        'potential_customers': potential_customers,
    }
    return render(request, 'payments/resolve_unreconciled.html', context)


@csrf_exempt
@require_http_methods(["POST"])
def mpesa_callback(request):
    """Handle M-Pesa STK callback"""
    # Check if the user has permission to process M-Pesa callbacks
    if not has_permission(request, 'process_mpesa_callback'):
        logger.warning("Permission denied for M-Pesa callback processing.")
        return JsonResponse({'ResultCode': 1, 'ResultDesc': 'Permission Denied'})

    try:
        data = json.loads(request.body)
        logger.info(f"M-Pesa callback received: {json.dumps(data, indent=2)}")

        # Extract callback data
        stkCallback = data.get('Body', {}).get('stkCallback', {})
        result_code = stkCallback.get('ResultCode')
        checkout_request_id = stkCallback.get('CheckoutRequestID')

        if result_code == 0:  # Success
            # Extract callback items
            callback_metadata = stkCallback.get('CallbackMetadata', {}).get('Item', [])
            callback_data = {}

            for item in callback_metadata:
                name = item.get('Name')
                value = item.get('Value')
                callback_data[name] = value

            amount = callback_data.get('Amount', 0)
            mpesa_receipt_number = callback_data.get('MpesaReceiptNumber', '')
            phone_number = callback_data.get('PhoneNumber', '')
            transaction_date = callback_data.get('TransactionDate')

            # Find customer by account reference (customer ID) from STK push
            customer = None
            try:
                # The account_reference should contain the customer ID from the STK push
                # First, try to get it from a stored STK transaction
                from payments.models import MpesaTransaction
                mpesa_transaction = MpesaTransaction.objects.filter(
                    checkout_request_id=checkout_request_id
                ).first()

                if mpesa_transaction and mpesa_transaction.account_reference:
                    # Try to find customer by customer ID
                    customer = Customer.objects.filter(
                        customer_id=mpesa_transaction.account_reference
                    ).first()

                    if customer:
                        logger.info(f"Found customer {customer.customer_id} from STK account reference")
                    else:
                        logger.warning(f"No customer found with ID: {mpesa_transaction.account_reference}")
                else:
                    logger.warning(f"No STK transaction found for checkout_request_id: {checkout_request_id}")

                # Fallback: try phone number matching if customer not found by ID
                if not customer:
                    logger.info("Falling back to phone number matching...")
                    phone_formats = [phone_number]

                    # Add variations of the phone number
                    if phone_number.startswith('254'):
                        phone_formats.append('0' + phone_number[3:])  # 0712345678
                        phone_formats.append('+' + phone_number)      # +254712345678
                    elif phone_number.startswith('0'):
                        phone_formats.append('254' + phone_number[1:])  # 254712345678
                        phone_formats.append('+254' + phone_number[1:]) # +254712345678
                    elif phone_number.startswith('+254'):
                        phone_formats.append(phone_number[1:])        # 254712345678
                        phone_formats.append('0' + phone_number[4:])  # 0712345678

                    # Try to find customer with any of these phone formats
                    for phone_format in phone_formats:
                        customer = Customer.objects.filter(phone_number=phone_format).first()
                        if customer:
                            logger.info(f"Found customer {customer.customer_id} with phone format: {phone_format}")
                            break

            except Exception as e:
                logger.error(f"Error finding customer: {str(e)}")


            if customer:
                try:
                    # Create payment record
                    payment = Payment.objects.create(
                        customer=customer,
                        amount=amount,
                        payment_method='mpesa',
                        status='completed',
                        mpesa_receipt_number=mpesa_receipt_number,
                        mpesa_phone_number=phone_number,
                        mpesa_callback_data=data,
                        reference_number=f"STK-{checkout_request_id}",
                        notes=f"STK Push payment - {mpesa_receipt_number}",
                        completed_at=timezone.now()
                    )

                # Update customer balance
                    from customers.services import CustomerBalanceService
                    CustomerBalanceService.add_balance(
                        customer=customer,
                        amount=amount,
                        description=f"M-Pesa payment - {mpesa_receipt_number}",
                        reference_id=str(payment.payment_id),
                        processed_by=None  # System processed
                    )

                    logger.info(f"Payment created successfully for customer {customer.customer_id}: KES {amount}")

                except Exception as payment_error:
                    logger.error(f"Error creating payment for customer {customer.customer_id}: {str(payment_error)}")
                    # Still create unreconciled payment as fallback
                    customer = None
            if not customer:
                # Create unreconciled payment
                from django.utils import timezone as django_timezone
                try:
                    UnreconciledPayment.objects.create(
                        transaction_id=mpesa_receipt_number,
                        phone_number=phone_number,
                        amount=amount,
                        account_reference=checkout_request_id,
                        transaction_time=django_timezone.now(),
                        first_name="Unknown",
                        last_name="STK Push",
                        reason='account_not_found',
                        callback_data=data
                    )
                    logger.warning(f"Customer not found for phone {phone_number}, created unreconciled payment with receipt {mpesa_receipt_number}")
                except Exception as unreconciled_error:
                    logger.error(f"Error creating unreconciled payment: {str(unreconciled_error)}")
        else:
            logger.warning(f"STK Push failed with result code {result_code}")

        return JsonResponse({'ResultCode': 0, 'ResultDesc': 'Success'})
    except Exception as e:
        logger.error(f"M-Pesa callback error: {str(e)}")
        return JsonResponse({'ResultCode': 1, 'ResultDesc': 'Error'})


@csrf_exempt
@require_http_methods(["POST"])
def mpesa_paybill_callback(request):
    """Handle M-Pesa Paybill callback"""
    if not has_permission(request, 'process_mpesa_paybill_callback'):
        logger.warning("Permission denied for M-Pesa paybill callback processing.")
        return JsonResponse({'ResultCode': 1, 'ResultDesc': 'Permission Denied'})

    try:
        data = json.loads(request.body)
        logger.info(f"M-Pesa paybill callback received: {json.dumps(data, indent=2)}")

        # Extract paybill transaction data
        trans_id = data.get('TransID', '')
        trans_time = data.get('TransTime', '')
        trans_amount = data.get('TransAmount', 0)
        business_short_code = data.get('BusinessShortCode', '')
        bill_ref_number = data.get('BillRefNumber', '')  # Customer account reference
        invoice_number = data.get('InvoiceNumber', '')
        org_account_balance = data.get('OrgAccountBalance', '')
        third_party_trans_id = data.get('ThirdPartyTransID', '')
        msisdn = data.get('MSISDN', '')  # Customer phone number
        first_name = data.get('FirstName', '')
        middle_name = data.get('MiddleName', '')
        last_name = data.get('LastName', '')

        if not trans_id or not trans_amount:
            logger.warning("Invalid paybill callback - missing transaction ID or amount")
            return JsonResponse({'ResultCode': 1, 'ResultDesc': 'Invalid data'})

        # Try to find customer by account reference (customer ID)
        customer = None
        if bill_ref_number:
            try:
                # First try exact customer ID match
                customer = Customer.objects.filter(customer_id=bill_ref_number).first()

                if not customer:
                    # Try phone number matching as fallback
                    phone_formats = [msisdn]

                    # Add variations of the phone number
                    if msisdn.startswith('254'):
                        phone_formats.append('0' + msisdn[3:])  # 0712345678
                        phone_formats.append('+' + msisdn)      # +254712345678
                    elif msisdn.startswith('0'):
                        phone_formats.append('254' + msisdn[1:])  # 254712345678
                        phone_formats.append('+254' + msisdn[1:]) # +254712345678
                    elif msisdn.startswith('+254'):
                        phone_formats.append(msisdn[1:])        # 254712345678
                        phone_formats.append('0' + msisdn[4:])  # 0712345678

                    # Try to find customer with any of these phone formats
                    for phone_format in phone_formats:
                        customer = Customer.objects.filter(phone=phone_format).first()
                        if customer:
                            logger.info(f"Found customer {customer.customer_id} by phone: {phone_format}")
                            break

            except Exception as e:
                logger.error(f"Error finding customer for paybill: {str(e)}")

        if customer:
            try:
                # Create payment record
                payment = Payment.objects.create(
                    customer=customer,
                    amount=trans_amount,
                    payment_method='mpesa',
                    status='completed',
                    mpesa_receipt_number=trans_id,
                    mpesa_phone_number=msisdn,
                    mpesa_callback_data=data,
                    reference_number=f"PAYBILL-{trans_id}",
                    notes=f"Paybill payment - Account ref: {bill_ref_number}",
                    completed_at=timezone.now()
                )

                # Update customer balance
                from customers.services import CustomerBalanceService
                CustomerBalanceService.add_balance(
                    customer=customer,
                    amount=trans_amount,
                    description=f"M-Pesa paybill payment - {trans_id}",
                    reference_id=str(payment.payment_id),
                    processed_by=None  # System processed
                )

                logger.info(f"Paybill payment processed for customer {customer.customer_id}: KES {trans_amount}")

            except Exception as payment_error:
                logger.error(f"Error creating paybill payment for customer {customer.customer_id}: {str(payment_error)}")
                # Still create unreconciled payment as fallback
                customer = None

        if not customer:
            # Create unreconciled payment
            try:
                UnreconciledPayment.objects.create(
                    transaction_id=trans_id,
                    phone_number=msisdn,
                    amount=trans_amount,
                    account_reference=bill_ref_number or "UNKNOWN",
                    transaction_time=timezone.now(),
                    first_name=first_name,
                    middle_name=middle_name,
                    last_name=last_name,
                    reason='account_not_found' if bill_ref_number else 'invalid_account',
                    callback_data=data
                )
                logger.warning(f"Customer not found for paybill payment {trans_id}, created unreconciled payment")
            except Exception as unreconciled_error:
                logger.error(f"Error creating unreconciled paybill payment: {str(unreconciled_error)}")

        return JsonResponse({'ResultCode': 0, 'ResultDesc': 'Success'})
    except Exception as e:
        logger.error(f"M-Pesa paybill callback error: {str(e)}")
        return JsonResponse({'ResultCode': 1, 'ResultDesc': 'Error'})


@csrf_exempt
@require_http_methods(["POST"])
def mpesa_paybill_validation(request):
    """Handle M-Pesa Paybill validation"""
    if not has_permission(request, 'validate_mpesa_paybill'):
        logger.warning("Permission denied for M-Pesa paybill validation.")
        return JsonResponse({'ResultCode': 1, 'ResultDesc': 'Permission Denied'})

    try:
        data = json.loads(request.body)
        # Handle validation logic here
        logger.info(f"M-Pesa validation received: {data}")
        return JsonResponse({'ResultCode': 0, 'ResultDesc': 'Success'})
    except Exception as e:
        logger.error(f"M-Pesa validation error: {str(e)}")
        return JsonResponse({'ResultCode': 1, 'ResultDesc': 'Rejected'})


@csrf_exempt
@require_http_methods(["POST"])
def mpesa_paybill_confirmation(request):
    """Handle M-Pesa Paybill confirmation"""
    if not has_permission(request, 'confirm_mpesa_paybill'):
        logger.warning("Permission denied for M-Pesa paybill confirmation.")
        return JsonResponse({'ResultCode': 1, 'ResultDesc': 'Permission Denied'})

    try:
        data = json.loads(request.body)
        logger.info(f"M-Pesa paybill confirmation received: {json.dumps(data, indent=2)}")

        # Process the confirmation - this is the main callback for paybill payments
        # Call the main paybill callback handler
        return mpesa_paybill_callback(request)

    except Exception as e:
        logger.error(f"M-Pesa paybill confirmation error: {str(e)}")
        return JsonResponse({'ResultCode': 1, 'ResultDesc': 'Error'})


@csrf_exempt
@require_http_methods(["POST"])
def mpesa_balance_callback(request):
    """Handle M-Pesa balance callback"""
    if not has_permission(request, 'process_mpesa_balance_callback'):
        logger.warning("Permission denied for M-Pesa balance callback processing.")
        return JsonResponse({'ResultCode': 1, 'ResultDesc': 'Permission Denied'})

    try:
        data = json.loads(request.body)
        # Handle balance callback logic here
        logger.info(f"M-Pesa balance callback received: {data}")
        return JsonResponse({'ResultCode': 0, 'ResultDesc': 'Success'})
    except Exception as e:
        logger.error(f"M-Pesa balance callback error: {str(e)}")
        return JsonResponse({'ResultCode': 1, 'ResultDesc': 'Error'})


@csrf_exempt
@require_http_methods(["POST"])
def mpesa_b2c_callback(request):
    """Handle M-Pesa B2C callback"""
    if not has_permission(request, 'process_mpesa_b2c_callback'):
        logger.warning("Permission denied for M-Pesa B2C callback processing.")
        return JsonResponse({'ResultCode': 1, 'ResultDesc': 'Permission Denied'})

    try:
        data = json.loads(request.body)
        # Handle B2C callback logic here
        logger.info(f"M-Pesa B2C callback received: {data}")
        return JsonResponse({'ResultCode': 0, 'ResultDesc': 'Success'})
    except Exception as e:
        logger.error(f"M-Pesa B2C callback error: {str(e)}")
        return JsonResponse({'ResultCode': 1, 'ResultDesc': 'Error'})


@csrf_exempt
@require_http_methods(["POST"])
def mpesa_b2b_callback(request):
    """Handle M-Pesa B2B callback"""
    if not has_permission(request, 'process_mpesa_b2b_callback'):
        logger.warning("Permission denied for M-Pesa B2B callback processing.")
        return JsonResponse({'ResultCode': 1, 'ResultDesc': 'Permission Denied'})

    try:
        data = json.loads(request.body)
        # Handle B2B callback logic here
        logger.info(f"M-Pesa B2B callback received: {data}")
        return JsonResponse({'ResultCode': 0, 'ResultDesc': 'Success'})
    except Exception as e:
        logger.error(f"M-Pesa B2B callback error: {str(e)}")
        return JsonResponse({'ResultCode': 1, 'ResultDesc': 'Error'})


@csrf_exempt
@require_http_methods(["POST"])
def mpesa_reversal_callback(request):
    """Handle M-Pesa reversal callback"""
    if not has_permission(request, 'process_mpesa_reversal_callback'):
        logger.warning("Permission denied for M-Pesa reversal callback processing.")
        return JsonResponse({'ResultCode': 1, 'ResultDesc': 'Permission Denied'})

    try:
        data = json.loads(request.body)
        # Handle reversal callback logic here
        logger.info(f"M-Pesa reversal callback received: {data}")
        return JsonResponse({'ResultCode': 0, 'ResultDesc': 'Success'})
    except Exception as e:
        logger.error(f"M-Pesa reversal callback error: {str(e)}")
        return JsonResponse({'ResultCode': 1, 'ResultDesc': 'Error'})


@login_required
def customer_payments(request, customer_id):
    """List payments for a specific customer"""
    if not has_permission(request, 'view_customer_payments'):
        messages.error(request, "You do not have permission to view customer payments.")
        return redirect('customers:customer_list') # Or another appropriate redirect

    customer = get_object_or_404(Customer, customer_id=customer_id)
    payments = Payment.objects.filter(customer=customer).order_by('-created_at')

    context = {
        'customer': customer,
        'payments': payments,
    }
    return render(request, 'payments/customer_payments.html', context)


@login_required
def payment_receipt(request, payment_id):
    """Generate payment receipt"""
    if not has_permission(request, 'view_payment_receipt'):
        messages.error(request, "You do not have permission to view payment receipts.")
        return redirect('payments:payment_list')

    payment = get_object_or_404(Payment, payment_id=payment_id)

    context = {
        'payment': payment,
    }
    return render(request, 'payments/payment_receipt.html', context)


@login_required
def payment_detail(request, payment_id):
    """View payment details"""
    if not has_permission(request, 'view_payment_detail'):
        messages.error(request, "You do not have permission to view payment details.")
        return redirect('payments:payment_list')

    payment = get_object_or_404(Payment, payment_id=payment_id)

    context = {
        'payment': payment,
    }
    return render(request, 'payments/payment_detail.html', context)