from datetime import date
from urllib.parse import quote

from django.contrib import messages
from django.contrib.admin.views.decorators import staff_member_required
from django.db import transaction
from django.db.models import Max, Q
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse
from django.views.decorators.http import require_POST
from reportlab.lib.pagesizes import A4
from reportlab.lib.units import mm
from reportlab.pdfgen import canvas

from .constants import PRODUCT_NAME, PRODUCT_PRICE, PRODUCT_WEIGHT, SHIPPING_TEXT, SUPPORT_PHONE
from .forms import OrderForm
from .models import Order


def next_order_id():
    today = date.today().strftime("%Y%m%d")
    prefix = f"MISRY-{today}-"
    latest = Order.objects.filter(order_id__startswith=prefix).aggregate(max_id=Max("order_id"))["max_id"]
    if not latest:
        return f"{prefix}001"
    return f"{prefix}{int(latest.rsplit('-', 1)[1]) + 1:03d}"


def whatsapp_url(order):
    message = "\n".join([
        "Hello, I want to order Misry Lehyam.",
        f"Name: {order.full_name}",
        f"Phone: {order.phone}",
        f"Address: {order.address}, {order.district}, {order.state} - {order.pincode}",
        f"Quantity: {order.quantity}",
        f"Total Amount: ₹{order.total_amount}",
        f"Payment Method: {order.payment_method}",
        f"Order ID: {order.order_id}",
    ])
    return f"https://wa.me/91{SUPPORT_PHONE}?text={quote(message)}"


def home(request):
    return render(request, "orders/home.html", {"form": OrderForm(), "product_price": PRODUCT_PRICE})


@require_POST
def create_order(request):
    form = OrderForm(request.POST)
    if not form.is_valid():
        for field_errors in form.errors.values():
            for error in field_errors:
                messages.error(request, error)
        return HttpResponseRedirect(f"{reverse('orders:home')}#pricing")

    with transaction.atomic():
        order = form.save(commit=False)
        order.order_id = next_order_id()
        order.save()

    messages.success(request, f"Order {order.order_id} placed successfully.")
    return redirect("orders:order_success", order_id=order.order_id)


def order_success(request, order_id):
    order = get_object_or_404(Order, order_id=order_id)
    return render(request, "orders/order_success.html", {
        "order": order,
        "product_name": PRODUCT_NAME,
        "product_price": PRODUCT_PRICE,
        "product_weight": PRODUCT_WEIGHT,
        "shipping_text": SHIPPING_TEXT,
        "support_phone": SUPPORT_PHONE,
        "whatsapp_url": whatsapp_url(order),
    })


@staff_member_required
def admin_orders(request):
    orders = Order.objects.all()
    query = request.GET.get("q", "").strip()
    order_status = request.GET.get("order_status", "").strip()
    payment_status = request.GET.get("payment_status", "").strip()

    if query:
        orders = orders.filter(Q(order_id__icontains=query) | Q(full_name__icontains=query) | Q(phone__icontains=query))
    if order_status:
        orders = orders.filter(order_status=order_status)
    if payment_status:
        orders = orders.filter(payment_status=payment_status)

    return render(request, "orders/admin_orders.html", {
        "orders": orders,
        "query": query,
        "order_status": order_status,
        "payment_status": payment_status,
        "order_status_choices": Order._meta.get_field("order_status").choices,
        "payment_status_choices": Order._meta.get_field("payment_status").choices,
    })


@require_POST
@staff_member_required
def update_order_status(request, order_id):
    order = get_object_or_404(Order, order_id=order_id)
    next_order_status = request.POST.get("order_status")
    next_payment_status = request.POST.get("payment_status")

    valid_order_statuses = {value for value, _label in Order._meta.get_field("order_status").choices}
    valid_payment_statuses = {value for value, _label in Order._meta.get_field("payment_status").choices}
    if next_order_status in valid_order_statuses:
        order.order_status = next_order_status
    if next_payment_status in valid_payment_statuses:
        order.payment_status = next_payment_status
    order.save(update_fields=["order_status", "payment_status"])
    messages.success(request, f"{order.order_id} updated.")
    return redirect("orders:admin_orders")


def invoice_pdf(request, order_id):
    order = get_object_or_404(Order, order_id=order_id)
    response = HttpResponse(content_type="application/pdf")
    response["Content-Disposition"] = f'attachment; filename="{order.order_id}-invoice.pdf"'

    pdf = canvas.Canvas(response, pagesize=A4)
    width, height = A4
    y = height - 28 * mm

    pdf.setFont("Helvetica-Bold", 22)
    pdf.drawString(24 * mm, y, "MISRY AYUR")
    y -= 10 * mm
    pdf.setFont("Helvetica", 10)
    pdf.drawString(24 * mm, y, f"Invoice: {order.order_id}")
    y -= 6 * mm
    pdf.drawString(24 * mm, y, f"Date: {order.created_at.strftime('%d %b %Y')}")
    y -= 6 * mm
    pdf.drawString(24 * mm, y, f"Support: {SUPPORT_PHONE}")

    y -= 14 * mm
    pdf.setFont("Helvetica-Bold", 12)
    pdf.drawString(24 * mm, y, "Customer Details")
    y -= 7 * mm
    pdf.setFont("Helvetica", 10)
    for line in [
        order.full_name,
        f"Phone: {order.phone}",
        f"Address: {order.address}",
        f"{order.district}, {order.state} - {order.pincode}",
    ]:
        pdf.drawString(24 * mm, y, line)
        y -= 6 * mm

    y -= 8 * mm
    pdf.setFont("Helvetica-Bold", 12)
    pdf.drawString(24 * mm, y, "Product")
    y -= 8 * mm
    pdf.setFont("Helvetica", 10)
    rows = [
        ("Product", f"{PRODUCT_NAME} ({PRODUCT_WEIGHT})"),
        ("Quantity", str(order.quantity)),
        ("Price", f"INR {PRODUCT_PRICE}"),
        ("Shipping", SHIPPING_TEXT),
        ("Payment", order.payment_method),
        ("Total", f"INR {order.total_amount}"),
    ]
    for label, value in rows:
        pdf.setFont("Helvetica-Bold", 10)
        pdf.drawString(24 * mm, y, label)
        pdf.setFont("Helvetica", 10)
        pdf.drawString(68 * mm, y, value)
        y -= 7 * mm

    pdf.showPage()
    pdf.save()
    return response
