from django import forms
from django.contrib.auth.decorators import login_required
from django.core.exceptions import ValidationError
from django.core.paginator import Paginator
from django.db.models import Count
from django.shortcuts import get_object_or_404, render, redirect
from django.utils import timezone
from django.views.decorators.cache import never_cache
from django.views.decorators.http import require_http_methods
from . import queries, services
from .forms import Filters, PolicyForm
from .models import SlaPolicy


@never_cache
@login_required(login_url="reporting:login")
@require_http_methods(["GET"])
def dashboard(request):
    at = timezone.now()
    form = Filters(request.GET, actor=request.user)
    rows = queries.records(request.user, at)
    if form.is_valid():
        if form.cleaned_data["center"]:
            rows = rows.filter(service_case__service_center=form.cleaned_data["center"])
        if form.cleaned_data["completed_since"]:
            rows = rows.filter(service_case__delivery_release__readied_at__date__gte=form.cleaned_data["completed_since"])
        counts = {r["sla_state"]: r["total"] for r in rows.order_by().values("sla_state").annotate(total=Count("pk"))}
        late_today = rows.filter(sla_state="COMPLETED_LATE", service_case__delivery_release__readied_at__date=timezone.localdate(at)).count()
        if form.cleaned_data["state"]:
            rows = rows.filter(sla_state=form.cleaned_data["state"])
    else:
        rows, counts, late_today = rows.none(), {}, 0
    page = Paginator(rows.order_by("due_at", "pk"), 25).get_page(request.GET.get("page"))
    query = request.GET.copy()
    query.pop("page", None)
    return render(request, "sla/dashboard.html", dict(form=form, page=page, observations=[queries.describe(r, at) for r in page],
        counts=counts, late_today=late_today, observed_at=at, filters=query.urlencode()), status=200 if form.is_valid() else 400)


@never_cache
@login_required(login_url="reporting:login")
@require_http_methods(["GET"])
def detail(request, pk):
    at = timezone.now()
    row = get_object_or_404(queries.records(request.user, at), service_case_id=pk)
    history = row.escalations.select_related("actor").prefetch_related("communication_attempts")
    return render(request, "sla/detail.html", dict(observation=queries.describe(row, at), history=history))


@never_cache
@login_required(login_url="reporting:login")
@require_http_methods(["GET"])
def policies(request):
    return render(request, "sla/policies.html", {"policies": SlaPolicy.objects.filter(company__in=queries.companies(request.user)).select_related("company", "service_center", "product_category")})


@never_cache
@login_required(login_url="reporting:login")
@require_http_methods(["GET", "POST"])
def policy_edit(request, pk=None):
    row = get_object_or_404(SlaPolicy.objects.filter(company__in=queries.companies(request.user)), pk=pk) if pk else None
    form = PolicyForm(request.POST if request.method == "POST" else None, actor=request.user, instance=row)
    if request.method == "POST" and form.is_valid():
        try:
            services.save_policy(actor=request.user, policy=row, **form.cleaned_data)
        except ValidationError as error:
            form.add_error(None, " ".join(error.messages))
        else:
            return redirect("sla:policies")
    return render(request, "sla/form.html", {"form": form, "title": "Manage SLA policy"}, status=400 if request.method == "POST" else 200)


@never_cache
@login_required(login_url="reporting:login")
@require_http_methods(["GET", "POST"])
def monitor_case(request, pk):
    case = get_object_or_404(queries.cases(request.user, "sla.monitor_sla"), pk=pk)
    form = forms.Form(request.POST if request.method == "POST" else None)
    if request.method == "POST" and form.is_valid():
        try:
            services.monitor(actor=request.user, company_id=case.company_id, service_center_id=case.service_center_id,
                             case_id=case.pk, origin="MANUAL")
        except ValidationError as error:
            form.add_error(None, " ".join(error.messages))
        else:
            return redirect("sla:dashboard")
    return render(request, "sla/form.html", {"form": form, "title": "Monitor SLA for " + case.job_number}, status=400 if request.method == "POST" else 200)
