import logging
from decimal import Decimal

from django.conf import settings
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse
from django.utils import timezone
from django.views.decorators.csrf import csrf_exempt

from accounts.delivery import (
    build_delivery_payload,
    delivery_payload_from_profile,
    derive_location_label,
    parse_decimal_value,
    phone_has_valid_digits,
    save_profile_delivery_defaults,
)
from cart.views import get_cart, save_cart
from products.models import Product

from .models import Order, OrderItem
from .payments import (
    PaymentGatewayError,
    build_esewa_redirect,
    construct_webhook_event,
    create_checkout_session,
    esewa_configured,
    initiate_khalti_payment,
    khalti_configured,
    payment_currency,
    retrieve_checkout_session,
    stripe_configured,
    stripe_value,
    verify_esewa_payment,
    verify_khalti_payment,
)

logger = logging.getLogger(__name__)

STATUS_SEQUENCE = ['Pending', 'Paid', 'Shipped', 'Delivered']
UNSET = object()


def _build_timeline(status):
    current_index = STATUS_SEQUENCE.index(status) if status in STATUS_SEQUENCE else 0
    timeline = []
    for idx, step in enumerate(STATUS_SEQUENCE):
        state = 'done' if idx < current_index else 'current' if idx == current_index else 'upcoming'
        timeline.append({'label': step, 'state': state})
    return timeline


def _get_checkout_source(request):
    buy_now = request.session.get('buy_now', {})
    if isinstance(buy_now, dict) and buy_now:
        return buy_now, 'buy_now'
    return get_cart(request), 'cart'



def _clear_checkout_source(request, source_key):
    if source_key == 'buy_now':
        request.session.pop('buy_now', None)
        request.session.modified = True
    else:
        save_cart(request, {})



def _build_delivery_shortcuts(user, profile, *, limit=4):
    shortcuts = []
    seen = set()
    default_full_name = user.get_full_name() or user.username

    def add_shortcut(
        identifier,
        *,
        badge,
        title,
        note='',
        full_name='',
        phone='',
        address='',
        location_label='',
        delivery_notes='',
        latitude=None,
        longitude=None,
        location_accuracy_m=None,
    ):
        payload = build_delivery_payload(
            full_name=full_name,
            phone=phone,
            address=address,
            location_label=location_label,
            delivery_notes=delivery_notes,
            latitude=latitude,
            longitude=longitude,
            location_accuracy_m=location_accuracy_m,
            save_as_default=True,
        )
        dedupe_key = (
            payload['phone'].lower(),
            payload['address'].lower(),
            payload['location_label'].lower(),
        )
        if not payload['address'] or dedupe_key in seen:
            return

        seen.add(dedupe_key)
        shortcuts.append(
            {
                'id': identifier,
                'badge': badge,
                'title': title,
                'note': note,
                'full_name': payload['full_name'],
                'phone': payload['phone'],
                'address': payload['address'],
                'location_label': payload['location_label'],
                'delivery_notes': payload['delivery_notes'],
                'latitude': payload['latitude'],
                'longitude': payload['longitude'],
                'location_accuracy_m': payload['location_accuracy_m'],
                'has_precise_location': bool(payload['latitude'] and payload['longitude']),
                'selected': False,
            }
        )

    if profile is not None and (profile.phone or profile.formatted_delivery_address):
        add_shortcut(
            'profile-default',
            badge='Saved profile',
            title=profile.short_location or 'Default account address',
            note='Use your currently saved checkout defaults.',
            full_name=default_full_name,
            phone=profile.phone,
            address=profile.formatted_delivery_address,
            location_label=profile.short_location,
            latitude=profile.latitude,
            longitude=profile.longitude,
            location_accuracy_m=profile.location_accuracy_m,
        )

    recent_orders = (
        Order.objects.filter(user=user)
        .exclude(address='')
        .order_by('-created_at')
        .only(
            'id',
            'full_name',
            'phone',
            'address',
            'location_label',
            'delivery_notes',
            'latitude',
            'longitude',
            'location_accuracy_m',
            'created_at',
        )
    )

    for order in recent_orders:
        add_shortcut(
            f'order-{order.id}',
            badge=f'Order #{order.id}',
            title=order.location_label or order.address.splitlines()[0].strip() or f'Order #{order.id}',
            note=f'Last used {order.created_at:%b %d, %Y}.',
            full_name=order.full_name or default_full_name,
            phone=order.phone,
            address=order.address,
            location_label=order.location_label,
            delivery_notes=order.delivery_notes,
            latitude=order.latitude,
            longitude=order.longitude,
            location_accuracy_m=order.location_accuracy_m,
        )
        if len(shortcuts) >= limit:
            break

    return shortcuts



def _resolve_delivery_shortcut(shortcuts, shortcut_id):
    if not shortcut_id:
        return None
    return next((shortcut for shortcut in shortcuts if shortcut['id'] == shortcut_id), None)



def _set_selected_delivery_shortcut(shortcuts, shortcut_id):
    for shortcut in shortcuts:
        shortcut['selected'] = shortcut['id'] == shortcut_id



def _render_checkout(request, *, cart_products, total, delivery, delivery_shortcuts):
    return render(
        request,
        'order/checkout.html',
        {
            'products': cart_products,
            'total': total,
            'delivery': delivery,
            'delivery_shortcuts': delivery_shortcuts,
        },
    )



def _save_order_updates(order, **changes):
    update_fields = []
    for field, value in changes.items():
        if value is UNSET:
            continue
        if getattr(order, field) != value:
            setattr(order, field, value)
            update_fields.append(field)
    if update_fields:
        order.save(update_fields=update_fields)



def _mark_order_paid(
    order,
    *,
    payment_method=UNSET,
    payment_provider=UNSET,
    payment_reference=UNSET,
    payment_session_id=UNSET,
    payment_currency_value=UNSET,
):
    _save_order_updates(
        order,
        status='Paid',
        payment_status='Paid',
        payment_method=payment_method,
        payment_provider=payment_provider,
        payment_reference=payment_reference,
        payment_session_id=payment_session_id,
        payment_currency=payment_currency_value,
        paid_at=order.paid_at or timezone.now(),
    )



def _mark_order_paid_from_stripe(order, session):
    payment_reference = stripe_value(session, 'payment_intent', '') or UNSET
    payment_session_id = stripe_value(session, 'id', '') or UNSET
    payment_currency_value = (stripe_value(session, 'currency', '') or settings.STRIPE_CURRENCY).upper()
    _mark_order_paid(
        order,
        payment_method='Card / Wallet',
        payment_provider='stripe',
        payment_reference=payment_reference,
        payment_session_id=payment_session_id,
        payment_currency_value=payment_currency_value,
    )



def _build_payment_options(order):
    stripe_ready = stripe_configured()
    esewa_ready = esewa_configured()
    khalti_ready = khalti_configured()

    options = [
        {
            'value': 'esewa',
            'title': 'eSewa ePay',
            'badge': 'Sandbox / UAT' if settings.ESEWA_SANDBOX else 'Live gateway',
            'badge_muted': not esewa_ready,
            'description': 'Redirect to the official eSewa wallet page and verify the transaction on return before marking the order paid.',
            'note': (
                'Ready to test with the official eSewa sandbox merchant.'
                if esewa_ready and settings.ESEWA_SANDBOX
                else 'Add your live eSewa merchant code and secret to switch this gateway to production.'
                if esewa_ready
                else 'Configure eSewa credentials to enable this wallet.'
            ),
            'ready': esewa_ready,
        },
        {
            'value': 'khalti',
            'title': 'Khalti',
            'badge': 'KPG-2',
            'badge_muted': not khalti_ready,
            'description': 'Create a real Khalti payment session on the server and verify its final status using the lookup API.',
            'note': (
                'Ready with your configured Khalti secret key.'
                if khalti_ready
                else 'Add KHALTI_SECRET_KEY to enable Khalti ePayment.'
            ),
            'ready': khalti_ready,
        },
        {
            'value': 'fonepay',
            'title': 'Fonepay',
            'badge': 'Merchant onboarding',
            'badge_muted': True,
            'description': 'Reserved for Fonepay Business / Dynamic QR integration once merchant onboarding details are available.',
            'note': 'Kept disabled so the app never claims a Fonepay payment succeeded without official verification.',
            'ready': False,
        },
    ]

    if stripe_ready:
        options.append(
            {
                'value': 'stripe',
                'title': 'Card / Wallet',
                'badge': 'Stripe Checkout',
                'badge_muted': False,
                'description': 'Fallback card checkout with Stripe, verified before the order is marked paid.',
                'note': f'Charges are created in {settings.STRIPE_CURRENCY.upper()} and verified on return/webhook.',
                'ready': True,
            }
        )

    options.append(
        {
            'value': 'cod',
            'title': 'Cash on Delivery',
            'badge': 'Offline',
            'badge_muted': True,
            'description': 'Confirm the order now and collect payment when the package arrives.',
            'note': 'You can still return later and switch to eSewa or Khalti before delivery.',
            'ready': True,
        }
    )

    ready_option_values = {option['value'] for option in options if option['ready']}
    selected_payment = None

    if order.payment_provider in ready_option_values:
        selected_payment = order.payment_provider
    elif order.payment_method == 'Cash on Delivery':
        selected_payment = 'cod'
    else:
        selected_payment = next((option['value'] for option in options if option['ready'] and option['value'] != 'cod'), 'cod')

    for option in options:
        option['checked'] = option['value'] == selected_payment

    online_ready = any(option['ready'] and option['value'] != 'cod' for option in options)

    return {
        'payment_options': options,
        'online_ready': online_ready,
        'stripe_ready': stripe_ready,
        'esewa_ready': esewa_ready,
        'khalti_ready': khalti_ready,
    }


@login_required
def checkout(request):
    source_items, source_key = _get_checkout_source(request)
    if not source_items:
        messages.warning(request, 'Your cart is empty. Add products before checking out.')
        return redirect('cart')

    cart_products = []
    total = Decimal('0')

    for id, qty in source_items.items():
        try:
            product_id = int(id)
            quantity = int(qty)
        except (TypeError, ValueError):
            continue

        if quantity <= 0:
            continue

        product = Product.objects.filter(id=product_id).first()
        if not product:
            messages.error(request, 'One of the selected products is no longer available.')
            _clear_checkout_source(request, source_key)
            return redirect('cart')

        if quantity > product.stock:
            if source_key == 'buy_now':
                messages.error(request, f'Only {product.stock} units of {product.name} are available.')
                _clear_checkout_source(request, source_key)
                return redirect('product_detail', product_id=product.id)

            messages.error(request, f'Only {product.stock} units of {product.name} are available.')
            return redirect('cart')

        product.qty = quantity
        product.subtotal = product.display_price * quantity
        total += product.subtotal
        cart_products.append(product)

    if not cart_products:
        messages.warning(request, 'No valid products found for checkout.')
        _clear_checkout_source(request, source_key)
        return redirect('cart')

    profile = getattr(request.user, 'profile', None)
    delivery_shortcuts = _build_delivery_shortcuts(request.user, profile)
    selected_shortcut_id = (
        request.POST.get('selected_shortcut_id', '').strip()
        if request.method == 'POST'
        else request.GET.get('delivery_shortcut', '').strip()
    )
    selected_shortcut = _resolve_delivery_shortcut(delivery_shortcuts, selected_shortcut_id)
    if selected_shortcut is None:
        selected_shortcut_id = ''
    _set_selected_delivery_shortcut(delivery_shortcuts, selected_shortcut_id)

    if request.method == 'POST':
        full_name = request.POST.get('full_name', '').strip()
        phone = request.POST.get('phone', '').strip()
        address = request.POST.get('address', '').strip()
        location_label = request.POST.get('location_label', '').strip()
        delivery_notes = request.POST.get('delivery_notes', '').strip()
        save_as_default = request.POST.get('save_as_default') == 'on'

        try:
            latitude = parse_decimal_value(
                request.POST.get('latitude'),
                field_label='latitude',
                minimum=Decimal('-90'),
                maximum=Decimal('90'),
            )
            longitude = parse_decimal_value(
                request.POST.get('longitude'),
                field_label='longitude',
                minimum=Decimal('-180'),
                maximum=Decimal('180'),
            )
            location_accuracy_m = parse_decimal_value(
                request.POST.get('location_accuracy_m'),
                field_label='location accuracy',
                minimum=Decimal('0'),
                maximum=Decimal('100000'),
            )
        except ValueError as exc:
            messages.error(request, str(exc))
            return _render_checkout(
                request,
                cart_products=cart_products,
                total=total,
                delivery=build_delivery_payload(
                    full_name=full_name,
                    phone=phone,
                    address=address,
                    location_label=location_label,
                    delivery_notes=delivery_notes,
                    latitude=request.POST.get('latitude', ''),
                    longitude=request.POST.get('longitude', ''),
                    location_accuracy_m=request.POST.get('location_accuracy_m', ''),
                    save_as_default=save_as_default,
                    selected_shortcut_id=selected_shortcut_id,
                ),
                delivery_shortcuts=delivery_shortcuts,
            )

        if (latitude is None) != (longitude is None):
            messages.error(request, 'GPS location is incomplete. Please retry the location button or continue without GPS.')
            return _render_checkout(
                request,
                cart_products=cart_products,
                total=total,
                delivery=build_delivery_payload(
                    full_name=full_name,
                    phone=phone,
                    address=address,
                    location_label=location_label,
                    delivery_notes=delivery_notes,
                    latitude=latitude,
                    longitude=longitude,
                    location_accuracy_m=location_accuracy_m,
                    save_as_default=save_as_default,
                    selected_shortcut_id=selected_shortcut_id,
                ),
                delivery_shortcuts=delivery_shortcuts,
            )

        location_label = derive_location_label(location_label, address)

        if not full_name or not phone or not address:
            messages.error(request, 'Please fill in full name, phone, and address.')
            return _render_checkout(
                request,
                cart_products=cart_products,
                total=total,
                delivery=build_delivery_payload(
                    full_name=full_name,
                    phone=phone,
                    address=address,
                    location_label=location_label,
                    delivery_notes=delivery_notes,
                    latitude=latitude,
                    longitude=longitude,
                    location_accuracy_m=location_accuracy_m,
                    save_as_default=save_as_default,
                    selected_shortcut_id=selected_shortcut_id,
                ),
                delivery_shortcuts=delivery_shortcuts,
            )

        if not phone_has_valid_digits(phone):
            messages.error(request, 'Please enter a valid phone number.')
            return _render_checkout(
                request,
                cart_products=cart_products,
                total=total,
                delivery=build_delivery_payload(
                    full_name=full_name,
                    phone=phone,
                    address=address,
                    location_label=location_label,
                    delivery_notes=delivery_notes,
                    latitude=latitude,
                    longitude=longitude,
                    location_accuracy_m=location_accuracy_m,
                    save_as_default=save_as_default,
                    selected_shortcut_id=selected_shortcut_id,
                ),
                delivery_shortcuts=delivery_shortcuts,
            )

        order = Order.objects.create(
            user=request.user,
            total_price=total,
            status='Pending',
            payment_status='Unpaid',
            payment_method='Pending selection',
            payment_currency=payment_currency(),
            full_name=full_name,
            phone=phone,
            address=address,
            location_label=location_label,
            latitude=latitude,
            longitude=longitude,
            location_accuracy_m=location_accuracy_m,
            delivery_notes=delivery_notes,
        )

        for product in cart_products:
            OrderItem.objects.create(order=order, product=product, quantity=product.qty, price=product.display_price)
            product.stock = max(product.stock - product.qty, 0)
            product.save(update_fields=['stock'])

        if save_as_default:
            save_profile_delivery_defaults(
                profile,
                phone=phone,
                address=address,
                location_label=location_label,
                latitude=latitude,
                longitude=longitude,
                location_accuracy_m=location_accuracy_m,
            )

        if location_label:
            request.session['delivery_location'] = location_label
        else:
            request.session.pop('delivery_location', None)

        _clear_checkout_source(request, source_key)
        messages.success(request, 'Order created successfully. Complete the payment step to finish checkout.')
        return redirect('payment', order_id=order.id)

    initial_delivery = delivery_payload_from_profile(
        profile,
        full_name=request.user.get_full_name() or request.user.username,
        selected_shortcut_id=selected_shortcut_id,
    )
    if selected_shortcut is not None:
        initial_delivery = build_delivery_payload(
            full_name=selected_shortcut['full_name'] or request.user.get_full_name() or request.user.username,
            phone=selected_shortcut['phone'],
            address=selected_shortcut['address'],
            location_label=selected_shortcut['location_label'],
            delivery_notes=selected_shortcut['delivery_notes'],
            latitude=selected_shortcut['latitude'],
            longitude=selected_shortcut['longitude'],
            location_accuracy_m=selected_shortcut['location_accuracy_m'],
            save_as_default=True,
            selected_shortcut_id=selected_shortcut_id,
        )

    return _render_checkout(
        request,
        cart_products=cart_products,
        total=total,
        delivery=initial_delivery,
        delivery_shortcuts=delivery_shortcuts,
    )


@login_required
def payment_page(request, order_id):
    order = get_object_or_404(Order, id=order_id, user=request.user)
    payment_context = _build_payment_options(order)

    if order.payment_status == 'Paid' or order.status == 'Paid':
        messages.info(request, 'This order has already been paid.')
        return redirect('order_detail', order_id=order.id)

    if request.GET.get('cancelled'):
        messages.warning(request, 'Payment was cancelled. Your order is still saved and waiting for payment.')

    if request.method == 'POST':
        method = request.POST.get('payment', '').strip()

        if method == 'esewa':
            if not payment_context['esewa_ready']:
                messages.error(request, 'eSewa is not configured yet. Add the merchant credentials to enable it.')
                return redirect('payment', order_id=order.id)

            try:
                gateway = build_esewa_redirect(request, order)
            except PaymentGatewayError as exc:
                messages.error(request, str(exc))
                return redirect('payment', order_id=order.id)
            except Exception:
                logger.exception('Unable to start eSewa payment for order %s', order.id)
                messages.error(request, 'We could not start the eSewa payment window right now. Please try again in a moment.')
                return redirect('payment', order_id=order.id)

            _save_order_updates(
                order,
                payment_method='eSewa',
                payment_provider='esewa',
                payment_status='Pending',
                payment_reference='',
                payment_session_id=gateway['session_id'],
                payment_currency=gateway['currency'],
            )
            return render(
                request,
                'order/payment_redirect.html',
                {
                    'order': order,
                    'gateway_name': 'eSewa',
                    'action_url': gateway['action_url'],
                    'fields': gateway['fields'],
                },
            )

        if method == 'khalti':
            if not payment_context['khalti_ready']:
                messages.error(request, 'Khalti is not configured yet. Add the Khalti secret key to enable it.')
                return redirect('payment', order_id=order.id)

            try:
                gateway = initiate_khalti_payment(request, order)
            except PaymentGatewayError as exc:
                messages.error(request, str(exc))
                return redirect('payment', order_id=order.id)
            except Exception:
                logger.exception('Unable to start Khalti payment for order %s', order.id)
                messages.error(request, 'We could not start Khalti right now. Please try again in a moment.')
                return redirect('payment', order_id=order.id)

            _save_order_updates(
                order,
                payment_method='Khalti',
                payment_provider='khalti',
                payment_status='Pending',
                payment_reference=gateway['reference'],
                payment_session_id=gateway['session_id'],
                payment_currency=gateway['currency'],
            )
            return redirect(gateway['payment_url'])

        if method == 'fonepay':
            messages.error(
                request,
                'Fonepay automation is intentionally disabled until the official merchant onboarding/API details are available.',
            )
            return redirect('payment', order_id=order.id)

        if method == 'stripe':
            if not payment_context['stripe_ready']:
                messages.error(request, 'Online card payments are not configured yet. Add a Stripe secret key to enable them.')
                return redirect('payment', order_id=order.id)

            try:
                session = create_checkout_session(request, order)
            except Exception:
                logger.exception('Unable to start Stripe Checkout for order %s', order.id)
                messages.error(request, 'We could not start the secure payment window right now. Please try again in a moment.')
                return redirect('payment', order_id=order.id)

            _save_order_updates(
                order,
                payment_method='Card / Wallet',
                payment_provider='stripe',
                payment_status='Pending',
                payment_currency=settings.STRIPE_CURRENCY.upper(),
                payment_session_id=stripe_value(session, 'id', '') or '',
            )

            checkout_url = stripe_value(session, 'url')
            if not checkout_url:
                messages.error(request, 'Stripe did not return a checkout URL. Please try again.')
                return redirect('payment', order_id=order.id)
            return redirect(checkout_url)

        if method == 'cod':
            _save_order_updates(
                order,
                payment_method='Cash on Delivery',
                payment_provider='offline',
                payment_status='Pending',
                payment_reference='',
                payment_session_id='',
                payment_currency=payment_currency(),
            )
            messages.success(request, 'Cash on delivery selected. You can still switch to an online wallet later if you want.')
            return redirect(f"{reverse('success')}?order_id={order.id}")

        messages.error(request, 'Please choose a supported payment method.')
        return redirect('payment', order_id=order.id)

    return render(
        request,
        'order/payment.html',
        {
            'order': order,
            'currency_code': payment_currency(),
            'esewa_sandbox': settings.ESEWA_SANDBOX,
            **payment_context,
        },
    )


@login_required
def payment_gateway(request, order_id, gateway):
    messages.info(request, 'Use the payment selection page to start the gateway securely.')
    return redirect('payment', order_id=order_id)


@login_required
def esewa_return(request):
    order_id = request.GET.get('order_id')
    order = get_object_or_404(Order, id=order_id, user=request.user)

    if order.payment_status == 'Paid':
        messages.info(request, 'This order has already been paid.')
        return redirect(f"{reverse('success')}?order_id={order.id}")

    if request.GET.get('failed'):
        _save_order_updates(
            order,
            payment_method='eSewa',
            payment_provider='esewa',
            payment_status='Failed',
            payment_currency=payment_currency(),
        )
        messages.warning(request, 'eSewa payment was not completed. Your order is still saved and waiting for payment.')
        return redirect('payment', order_id=order.id)

    try:
        result = verify_esewa_payment(order, request.GET.get('data', ''))
    except PaymentGatewayError as exc:
        logger.warning('Unable to verify eSewa payment for order %s: %s', order.id, exc)
        messages.error(request, str(exc))
        return redirect('payment', order_id=order.id)
    except Exception:
        logger.exception('Unexpected eSewa verification error for order %s', order.id)
        messages.error(request, 'We could not verify the eSewa payment yet. Please try again.')
        return redirect('payment', order_id=order.id)

    if result['status'] == 'Paid':
        _mark_order_paid(
            order,
            payment_method='eSewa',
            payment_provider='esewa',
            payment_reference=result['reference'],
            payment_session_id=result['session_id'],
            payment_currency_value=result['currency'],
        )
        messages.success(request, result['message'])
        return redirect(f"{reverse('success')}?order_id={order.id}")

    if result['status'] == 'Pending':
        _save_order_updates(
            order,
            payment_method='eSewa',
            payment_provider='esewa',
            payment_status='Pending',
            payment_session_id=result['session_id'],
            payment_currency=result['currency'],
        )
        messages.info(request, result['message'])
    else:
        _save_order_updates(
            order,
            payment_method='eSewa',
            payment_provider='esewa',
            payment_status='Failed',
            payment_session_id=result['session_id'],
            payment_currency=result['currency'],
        )
        messages.warning(request, result['message'])

    return redirect('payment', order_id=order.id)


@login_required
def khalti_return(request):
    order_id = request.GET.get('order_id')
    order = get_object_or_404(Order, id=order_id, user=request.user)

    if order.payment_status == 'Paid':
        messages.info(request, 'This order has already been paid.')
        return redirect(f"{reverse('success')}?order_id={order.id}")

    pidx = request.GET.get('pidx', '').strip()
    if not pidx:
        _save_order_updates(
            order,
            payment_method='Khalti',
            payment_provider='khalti',
            payment_status='Failed',
            payment_currency=payment_currency(),
        )
        messages.warning(request, 'Khalti payment was not completed. Your order is still saved and waiting for payment.')
        return redirect('payment', order_id=order.id)

    try:
        result = verify_khalti_payment(order, pidx)
    except PaymentGatewayError as exc:
        logger.warning('Unable to verify Khalti payment for order %s: %s', order.id, exc)
        messages.error(request, str(exc))
        return redirect('payment', order_id=order.id)
    except Exception:
        logger.exception('Unexpected Khalti verification error for order %s', order.id)
        messages.error(request, 'We could not verify the Khalti payment yet. Please try again.')
        return redirect('payment', order_id=order.id)

    if result['status'] == 'Paid':
        _mark_order_paid(
            order,
            payment_method='Khalti',
            payment_provider='khalti',
            payment_reference=result['reference'],
            payment_session_id=result['session_id'],
            payment_currency_value=result['currency'],
        )
        messages.success(request, result['message'])
        return redirect(f"{reverse('success')}?order_id={order.id}")

    if result['status'] == 'Pending':
        _save_order_updates(
            order,
            payment_method='Khalti',
            payment_provider='khalti',
            payment_status='Pending',
            payment_session_id=result['session_id'],
            payment_currency=result['currency'],
        )
        messages.info(request, result['message'])
    else:
        _save_order_updates(
            order,
            payment_method='Khalti',
            payment_provider='khalti',
            payment_status='Failed',
            payment_session_id=result['session_id'],
            payment_currency=result['currency'],
        )
        messages.warning(request, result['message'])

    return redirect('payment', order_id=order.id)


@login_required
def success(request):
    order_id = request.GET.get('order_id')
    session_id = request.GET.get('session_id', '').strip()

    if not order_id:
        messages.info(request, 'Open an order to view its payment status.')
        return redirect('my_orders')

    order = get_object_or_404(Order, id=order_id, user=request.user)
    payment_verified = order.payment_status == 'Paid'
    verification_message = 'Your order has been created successfully.'

    if session_id:
        if not stripe_configured():
            verification_message = 'The order exists, but Stripe is not configured on the server to verify the payment session.'
        else:
            try:
                session = retrieve_checkout_session(session_id)
            except Exception:
                logger.exception('Unable to verify Stripe checkout session %s for order %s', session_id, order.id)
                verification_message = 'We could not verify the payment yet. Please refresh this page or open the order details page.'
            else:
                metadata = stripe_value(session, 'metadata', {}) or {}
                session_order_id = str(metadata.get('order_id') or stripe_value(session, 'client_reference_id', '') or '')
                if session_order_id != str(order.id):
                    verification_message = 'The returned payment session did not match this order, so payment could not be confirmed.'
                elif stripe_value(session, 'payment_status') == 'paid':
                    _mark_order_paid_from_stripe(order, session)
                    payment_verified = True
                    verification_message = 'Payment verified successfully. Your order is confirmed.'
                else:
                    verification_message = 'Your order was created, but Stripe has not marked the payment as paid yet.'
    elif order.payment_status == 'Paid':
        payment_verified = True
        verification_message = 'Payment verified successfully. Your order is confirmed.'
    elif order.payment_status == 'Failed':
        provider_name = order.payment_provider_label if order.payment_provider else 'payment gateway'
        verification_message = f'The last {provider_name} attempt did not complete. You can retry from the payment page.'
    elif order.payment_method == 'Cash on Delivery':
        verification_message = 'Your order is confirmed. Payment will be collected on delivery, and you can still switch to an online wallet before shipment if needed.'
    elif order.payment_provider == 'esewa':
        verification_message = 'Your order was created, but eSewa has not marked the payment as complete yet.'
    elif order.payment_provider == 'khalti':
        verification_message = 'Your order was created, but Khalti has not marked the payment as complete yet.'
    elif order.payment_provider == 'stripe':
        verification_message = 'Your order was created, but Stripe has not marked the payment as complete yet.'
    else:
        verification_message = 'Your order is waiting for payment. You can return to the payment page any time.'

    return render(
        request,
        'order/success.html',
        {
            'order': order,
            'payment_verified': payment_verified,
            'verification_message': verification_message,
        },
    )


@csrf_exempt
def stripe_webhook(request):
    if request.method != 'POST':
        return HttpResponse(status=405)

    if not stripe_configured() or not settings.STRIPE_WEBHOOK_SECRET:
        return HttpResponse('Stripe webhook is not configured.', status=503)

    signature = request.META.get('HTTP_STRIPE_SIGNATURE', '')

    try:
        event = construct_webhook_event(request.body, signature)
    except Exception:
        logger.exception('Invalid Stripe webhook received')
        return HttpResponse(status=400)

    event_type = event.get('type', '')
    session = event.get('data', {}).get('object', {})
    metadata = stripe_value(session, 'metadata', {}) or {}
    order_id = str(metadata.get('order_id') or stripe_value(session, 'client_reference_id', '') or '').strip()
    order = Order.objects.filter(id=order_id).first() if order_id else None

    if order and event_type in {'checkout.session.completed', 'checkout.session.async_payment_succeeded'}:
        _mark_order_paid_from_stripe(order, session)
    elif order and event_type == 'checkout.session.expired' and order.payment_status != 'Paid':
        _save_order_updates(order, payment_status='Failed')

    return HttpResponse(status=200)


@login_required
def my_orders(request):
    status_filter = request.GET.get('status', '').strip()
    payment_filter = request.GET.get('payment', '').strip()

    valid_statuses = [choice[0] for choice in Order.STATUS_CHOICES]
    valid_payment_statuses = [choice[0] for choice in Order.PAYMENT_STATUS_CHOICES]

    if status_filter not in valid_statuses:
        status_filter = ''
    if payment_filter not in valid_payment_statuses:
        payment_filter = ''

    base_orders = Order.objects.filter(user=request.user)
    orders = base_orders.prefetch_related('items__product').order_by('-created_at')

    if status_filter:
        orders = orders.filter(status=status_filter)
    if payment_filter:
        orders = orders.filter(payment_status=payment_filter)

    order_summary = {
        'total': base_orders.count(),
        'paid': base_orders.filter(payment_status='Paid').count(),
        'pending_payment': base_orders.exclude(payment_status='Paid').count(),
        'shipped': base_orders.filter(status='Shipped').count(),
        'delivered': base_orders.filter(status='Delivered').count(),
    }

    return render(
        request,
        'order/my_orders.html',
        {
            'orders': orders,
            'order_summary': order_summary,
            'status_filters': valid_statuses,
            'payment_filters': valid_payment_statuses,
            'selected_status': status_filter,
            'selected_payment_status': payment_filter,
            'has_order_filters': bool(status_filter or payment_filter),
        },
    )


@login_required
def order_detail(request, order_id):
    order = get_object_or_404(Order.objects.prefetch_related('items__product'), id=order_id, user=request.user)
    timeline = _build_timeline(order.status)
    return render(request, 'order/order_detail.html', {'order': order, 'timeline': timeline})
