from datetime import timedelta
from decimal import Decimal
import re

from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.shortcuts import get_object_or_404, redirect, render
from django.utils import timezone

from cart.views import get_cart, save_cart
from products.models import Product

from .models import Order, OrderItem


STATUS_SEQUENCE = ['Pending', 'Paid', 'Shipped', 'Delivered']


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 _sync_demo_status(order):
    elapsed = timezone.now() - order.created_at
    if elapsed >= timedelta(minutes=3):
        target = 'Delivered'
    elif elapsed >= timedelta(minutes=2):
        target = 'Shipped'
    elif elapsed >= timedelta(minutes=1):
        target = 'Paid'
    else:
        target = 'Pending'

    current_index = STATUS_SEQUENCE.index(order.status) if order.status in STATUS_SEQUENCE else 0
    target_index = STATUS_SEQUENCE.index(target)
    if target_index > current_index:
        order.status = target
        order.save(update_fields=['status'])


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 _validate_phone(phone):
    digits = re.sub(r'\D+', '', phone)
    return 7 <= len(digits) <= 15


@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')

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

        if not full_name or not phone or not address:
            messages.error(request, 'Please fill in full name, phone, and address.')
            return render(
                request,
                'order/checkout.html',
                {
                    'products': cart_products,
                    'total': total,
                    'delivery': {
                        'full_name': full_name,
                        'phone': phone,
                        'address': address,
                    },
                },
            )

        if not _validate_phone(phone):
            messages.error(request, 'Please enter a valid phone number.')
            return render(
                request,
                'order/checkout.html',
                {
                    'products': cart_products,
                    'total': total,
                    'delivery': {
                        'full_name': full_name,
                        'phone': phone,
                        'address': address,
                    },
                },
            )

        order = Order.objects.create(
            user=request.user,
            total_price=total,
            status='Pending',
            full_name=full_name,
            phone=phone,
            address=address,
        )

        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'])

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

    return render(
        request,
        'order/checkout.html',
        {
            'products': cart_products,
            'total': total,
            'delivery': {
                'full_name': request.user.get_full_name(),
                'phone': '',
                'address': '',
            },
        },
    )


GATEWAY_OPTIONS = {
    'esewa': {
        'name': 'eSewa',
        'description': 'Pay securely using eSewa mobile wallet or QR code.',
        'button_text': 'Pay with eSewa',
    },
    'khalti': {
        'name': 'Khalti',
        'description': 'Complete payment instantly with Khalti.',
        'button_text': 'Pay with Khalti',
    },
    'fonpay': {
        'name': 'Fonpay',
        'description': 'Use Fonpay to pay from your mobile wallet.',
        'button_text': 'Pay with Fonpay',
    },
}


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

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

    if request.method == 'POST':
        method = request.POST.get('payment')
        if not method:
            messages.error(request, 'Please select a payment method.')
            return redirect('payment', order_id=order.id)

        method_key = method.lower().replace(' ', '')
        if method_key in GATEWAY_OPTIONS:
            return redirect('payment_gateway', order_id=order.id, gateway=method_key)

        if method == 'Cash on Delivery':
            order.payment_method = method
            order.status = 'Paid'
            order.save(update_fields=['payment_method', 'status'])
            messages.success(request, 'Cash on Delivery selected. Your order is confirmed.')
            return redirect('success')

        messages.error(request, 'Selected payment method is not supported.')
        return redirect('payment', order_id=order.id)

    return render(request, 'order/payment.html', {'order': order, 'gateways': GATEWAY_OPTIONS})


@login_required
def payment_gateway(request, order_id, gateway):
    order = get_object_or_404(Order, id=order_id, user=request.user)

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

    gateway_data = GATEWAY_OPTIONS.get(gateway)
    if gateway_data is None:
        messages.error(request, 'Selected payment gateway is not available.')
        return redirect('payment', order_id=order.id)

    if request.method == 'POST':
        order.payment_method = gateway_data['name']
        order.status = 'Paid'
        order.save(update_fields=['payment_method', 'status'])
        messages.success(request, f'Payment completed through {gateway_data["name"]}.')
        return redirect('success')

    return render(request, 'order/payment_gateway.html', {'order': order, 'gateway': gateway_data})


def success(request):
    return render(request, 'order/success.html')


@login_required
def my_orders(request):
    orders = list(Order.objects.filter(user=request.user).order_by('-created_at'))
    for order in orders:
        _sync_demo_status(order)
    return render(request, 'order/my_orders.html', {'orders': orders})


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