#
# Copyright 2023 © AE UTBM
# ae@utbm.fr / ae.info@utbm.fr
#
# This file is part of the website of the UTBM Student Association (AE UTBM),
# https://ae.utbm.fr.
#
# You can find the source code of the website at https://github.com/ae-utbm/sith
#
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3)
# SEE : https://raw.githubusercontent.com/ae-utbm/sith/master/LICENSE
# OR WITHIN THE LOCAL FILE "LICENSE"
#
#
from datetime import timedelta

from django.conf import settings
from django.core.exceptions import PermissionDenied
from django.db.models import F
from django.http import HttpRequest, HttpResponseRedirect
from django.shortcuts import redirect
from django.urls import reverse
from django.utils import timezone
from django.utils.safestring import SafeString
from django.views.decorators.http import require_POST
from django.views.generic import DetailView
from django.views.generic.detail import SingleObjectMixin
from django.views.generic.edit import FormView

from core.auth.mixins import CanViewMixin
from core.views import FragmentMixin, UseFragmentsMixin
from counter.forms import CounterLoginForm, GetUserForm
from counter.middleware import SESSION_PERMANENCES_KEY
from counter.models import Counter, Permanency
from counter.utils import is_logged_in_counter
from counter.views.mixins import CounterTabsMixin


class CounterLoginFragment(FragmentMixin, SingleObjectMixin, FormView):
    model = Counter
    form_class = CounterLoginForm
    reload_on_redirect = True
    pk_url_kwarg = "counter_id"
    template_name = "counter/fragments/login.jinja"

    def dispatch(self, request, *args, **kwargs):
        self.object = self.get_object()
        if self.object.type != "BAR":
            # barmen have to log in only if it is a bar,
            # so calling this view on a non-bar counter makes no sense
            raise PermissionDenied
        return super().dispatch(request, *args, **kwargs)

    def get_form_kwargs(self):
        return super().get_form_kwargs() | {
            "request": self.request,
            "counter": self.object,
        }

    def form_valid(self, form: CounterLoginForm):
        user = form.get_user()
        perm = self.object.permanencies.create(user=user, start=timezone.now())
        self.request.session.setdefault(SESSION_PERMANENCES_KEY, []).append(perm.id)
        self.request.session.modified = True
        self.success_url = reverse(
            "counter:details", kwargs={"counter_id": self.object.id}
        )
        return super().form_valid(form)

    def render_fragment(self, request, **kwargs) -> SafeString:
        self.object = kwargs.pop("counter")
        return super().render_fragment(request, **kwargs)

    def get_context_data(self, **kwargs):
        return super().get_context_data(**kwargs) | {
            "action": reverse("counter:login", kwargs={"counter_id": self.object.id})
        }


@require_POST
def counter_logout(request: HttpRequest, counter_id: int) -> HttpResponseRedirect:
    """End the permanency of a user in this counter."""
    Permanency.objects.filter(
        counter=counter_id, user=request.POST["user_id"], end=None
    ).update(end=F("activity"))
    return redirect("counter:details", counter_id=counter_id)


class CounterMain(
    CounterTabsMixin, UseFragmentsMixin, CanViewMixin, SingleObjectMixin, FormView
):
    """The public (barman) view."""

    model = Counter
    queryset = Counter.objects.exclude(type="EBOUTIC")
    template_name = "counter/counter_main.jinja"
    pk_url_kwarg = "counter_id"
    form_class = GetUserForm
    current_tab = "counter"

    def dispatch(self, request, *args, **kwargs):
        self.object: Counter = self.get_object()
        if self.object.type == "BAR":
            self.object.update_activity()
        return super().dispatch(request, *args, **kwargs)

    def get_fragment_context_data(self) -> dict[str, SafeString]:
        login_fragment = (
            CounterLoginFragment.as_fragment()(self.request, counter=self.object)
            if self.object.type == "BAR"
            else ""
        )
        return super().get_fragment_context_data() | {"login_fragment": login_fragment}

    def get_context_data(self, **kwargs):
        """We handle here the login form for the barman."""
        kwargs = super().get_context_data(**kwargs)
        if self.object.type == "BAR":
            kwargs["barmen"] = self.object.barmen_list
            kwargs["barmen_here"] = list(
                self.request.barmen.intersection(self.object.barmen_list)
            )
        kwargs["can_click"] = (
            self.object.type == "BAR"
            and self.request.barmen
            and self.request.barmen.issubset(set(self.object.barmen_list))
        ) or (
            self.object.type == "OFFICE"
            and (
                self.object.sellers.contains(self.request.user)
                or self.object.club.has_rights_in_club(self.request.user)
            )
        )
        if "last_basket" in self.request.session:
            kwargs["last_basket"] = self.request.session.pop("last_basket")
            kwargs["last_customer"] = self.request.session.pop("last_customer")
            kwargs["last_total"] = self.request.session.pop("last_total")
            kwargs["new_customer_amount"] = self.request.session.pop(
                "new_customer_amount"
            )
        return kwargs

    def form_valid(self, form: GetUserForm):
        """We handle here the redirection, passing the user id of the asked customer."""
        self.success_url = reverse(
            "counter:click",
            kwargs={
                "counter_id": self.kwargs["counter_id"],
                "user_id": form.cleaned_data["user_id"],
            },
        )
        return super().form_valid(form)


class CounterLastOperationsView(CounterTabsMixin, CanViewMixin, DetailView):
    """Provide the last operations to allow barmen to delete them."""

    model = Counter
    pk_url_kwarg = "counter_id"
    template_name = "counter/last_ops.jinja"
    current_tab = "last_ops"

    def dispatch(self, request, *args, **kwargs):
        """We have here again a very particular right handling."""
        self.object = self.get_object()
        if is_logged_in_counter(request) and self.object.barmen_list:
            return super().dispatch(request, *args, **kwargs)
        return HttpResponseRedirect(
            reverse("counter:details", kwargs={"counter_id": self.object.id})
            + "?bad_location"
        )

    def get_context_data(self, **kwargs):
        """Add form to the context."""
        kwargs = super().get_context_data(**kwargs)
        threshold = timezone.now() - timedelta(
            minutes=settings.SITH_LAST_OPERATIONS_LIMIT
        )
        kwargs["last_refillings"] = (
            self.object.refillings.filter(date__gte=threshold)
            .select_related("operator", "customer__user")
            .order_by("-id")[:20]
        )
        kwargs["last_sellings"] = (
            self.object.sellings.filter(date__gte=threshold)
            .select_related("seller", "customer__user")
            .order_by("-id")[:20]
        )
        return kwargs


class CounterActivityView(DetailView):
    """Show the bar activity."""

    model = Counter
    pk_url_kwarg = "counter_id"
    template_name = "counter/activity.jinja"
