from django.contrib.auth.decorators import login_required
from django.core.exceptions import PermissionDenied, ValidationError
from django.core.paginator import Paginator
from django.db import DatabaseError
from django.db.migrations.exceptions import InconsistentMigrationHistory
from django.shortcuts import render, get_object_or_404, redirect
from django.views.decorators.cache import never_cache
from django.views.decorators.http import require_GET, require_http_methods
from apps.operations.queries import centers
from apps.frontdesk.forms import SlotForm, ConfigureSlotForm
from apps.frontdesk.models import AppointmentSlot
from apps.frontdesk import services
from .navigation import visible, sections, system_administrator


@never_cache
@login_required(login_url="operations:login")
@require_GET
def index(request):
    from apps.operations.context import shell
    from .workspace import metrics
    capabilities = shell(request)["workspace"]["capabilities"] if request.user.is_active else {}
    def can(permission, company_only=False):
        return capabilities.get((permission, company_only), False)
    if not visible(request, can):
        raise PermissionDenied
    groups = sections(request, can)
    search = request.GET.get("q", "")[:100].strip()
    if search:
        groups = [dict(group, links=[(label, url) for label, url in group["links"]
                  if search.casefold() in (group["label"] + " " + label).casefold()]) for group in groups]
        groups = [group for group in groups if group["links"]]
    return render(request, "configuration/index.html", {"title": "Administration / Settings",
        "sections": groups, "metrics": metrics(request, can), "search": search})


@never_cache
@login_required(login_url="operations:login")
@require_GET
def readiness(request):
    if not system_administrator(request.user):
        raise PermissionDenied
    from .readiness import inspect_installation, is_ready
    try:
        checks = inspect_installation()
    except (DatabaseError,InconsistentMigrationHistory):
        return render(request,"configuration/readiness.html",{"title":"Installation readiness", "unavailable":True},status=503)
    return render(request,"configuration/readiness.html",{"title":"Installation readiness","checks":checks,"ready":is_ready(checks)})


@never_cache
@login_required(login_url="operations:login")
@require_GET
def slots(request,center_id=None):
    allowed = centers(request.user,"frontdesk.manage_slots").select_related("company")
    center = get_object_or_404(allowed,pk=center_id) if center_id else None
    page = Paginator(AppointmentSlot.objects.filter(service_center=center).order_by("-date","start_time","pk") if center
                     else allowed.order_by("company__code","code"),25).get_page(request.GET.get("page"))
    return render(request,"configuration/slots.html",{"title":"Appointment configuration","center":center,"page":page})


@never_cache
@login_required(login_url="operations:login")
@require_http_methods(["GET","POST"])
def slot_edit(request,center_id,pk=None):
    center = get_object_or_404(centers(request.user,"frontdesk.manage_slots"),pk=center_id)
    row = get_object_or_404(AppointmentSlot,pk=pk,service_center=center) if pk else None
    form = (ConfigureSlotForm if row else SlotForm)(request.POST if request.method=="POST" else None,
        initial={"capacity":row.capacity,"is_active":row.is_active} if row else None)
    if request.method=="POST" and form.is_valid():
        try:
            if row:
                services.configure_slot(actor=request.user,slot=row,**form.cleaned_data)
            else:
                services.create_slot(actor=request.user,service_center=center,**form.cleaned_data)
        except ValidationError as error:
            form.add_error(None," ".join(error.messages))
        else:
            return redirect("configuration:center_slots",center_id=center.pk)
    return render(request,"configuration/form.html",{"title":"Configure appointment availability","form":form,"center":center},
                  status=400 if request.method=="POST" else 200)
