from django import http
from django.contrib.auth.mixins import UserPassesTestMixin
from django.shortcuts import get_object_or_404, render
from django.urls import reverse, reverse_lazy
from django.utils import timezone
from django.views import generic

from la_chariotte.mail.utils import send_order_confirmation_mail

from ..models import GroupedOrder, Order, OrderAuthor, OrderedItem


def place_order(request, code):
    # Creates an AnonymousUser and an Order with related OrderedItems
    grouped_order = get_object_or_404(GroupedOrder, code=code)

    # Handle permissions
    user_is_orga = request.user == grouped_order.orga
    is_to_be_delivered = grouped_order.is_to_be_delivered()
    is_open = grouped_order.is_open()

    access_allowed = is_open or (user_is_orga and is_to_be_delivered)

    if not access_allowed:
        return http.HttpResponseForbidden()

    # get a dict with quantity_{{item_id}}:[ {{ quantity on phone }},{{ quantity on desktop }} ]
    orders_dict = {
        key: request.POST.getlist(key)
        for key, value in request.POST.items()
        if key.startswith("quantity")
    }

    # transform it into quantity_{{item_id}}: {{ greatest of the two quantities }}
    for i in orders_dict:
        value = (
            orders_dict[i][0]
            if orders_dict[i][0] >= orders_dict[i][1]
            else orders_dict[i][1]
        )
        orders_dict[i] = value

    # create an order
    first_name = request.POST["first_name"]
    last_name = request.POST["last_name"]
    phone = request.POST["phone"]
    email = request.POST["email"]
    note = request.POST["note"]
    author = OrderAuthor.objects.create(
        first_name=first_name, last_name=last_name, email=email, phone=phone
    )
    order = Order.objects.create(
        author=author,
        grouped_order=grouped_order,
        note=note,
        created_date=timezone.now(),
    )

    # add items to the order
    error_message = None
    for key, quantity in orders_dict.items():
        quantity = int(quantity)
        item = grouped_order.item_set.get(pk=key.split("_")[1])
        # check if too many items are ordered
        error_message = validate_item_ordered_nb(item, quantity)
        if error_message:
            break  # stop creating items if there is an error
        if quantity > 0:
            OrderedItem.objects.create(nb=quantity, order=order, item=item)

    # Redisplay the form with error messages if there is an error
    if error_message:
        order.delete()
        author.delete()
        return render(
            request,
            "order/grouped_order_detail.html",
            {
                "grouped_order": grouped_order,
                "error_message": error_message,
                "note": order.note,
                "author": author,
            },
        )

    # check if the order contains articles
    error_message = validate_articles_ordered_nb(order)

    # Redisplay the form with error messages if there is an error
    if error_message:
        order.delete()
        author.delete()
        return render(
            request,
            "order/grouped_order_detail.html",
            {
                "grouped_order": grouped_order,
                "error_message": error_message,
                "note": order.note,
                "author": author,
            },
        )

    # Send confirmation mail and redirect to confirmation page
    send_order_confirmation_mail(order)

    # Redirect to prevent data from being posted twice when the user hits the Back
    # button.
    return http.HttpResponseRedirect(
        reverse("order:order_confirm", args=(grouped_order.code, order.pk))
    )


def validate_item_ordered_nb(item, ordered_nb):
    """Returns an error message if the ordered items are not available"""
    if item.get_remaining_nb() is not None and item.get_remaining_nb() - ordered_nb < 0:
        return f"Trop de {item.name} commandés pour la quantité disponible"
    return None


def validate_articles_ordered_nb(order):
    """Return an error if no items are ordered"""
    if order.articles_nb == 0:
        return "Veuillez commander au moins un produit"
    return None


class OrderDetailView(generic.DetailView):
    model = Order


class OrderDeleteView(UserPassesTestMixin, generic.DeleteView):
    model = Order

    def get_success_url(self):
        return reverse_lazy(
            "order:grouped_order_overview", args=[self.object.grouped_order.code]
        )

    def test_func(self):
        # Restrict access to the manager or a superuser
        return (
            self.get_object().grouped_order.orga == self.request.user
            or self.request.user.is_superuser
        )
