from django import forms
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.core.exceptions import ValidationError
from django.core.paginator import Paginator
from django.shortcuts import get_object_or_404, render, redirect
from django.views.decorators.cache import never_cache
from django.views.decorators.http import require_http_methods

from . import queries, services
from .forms import TemplateForm, ManualForm
from .models import NotificationTemplate


@never_cache
@login_required(login_url="reporting:login")
@require_http_methods(["GET"])
def history(request):
    rows = queries.history(request.user).select_related("customer", "service_center").prefetch_related("attempts").order_by("-created_at")
    page = Paginator(rows, 30).get_page(request.GET.get("page"))
    can_send = set(queries.history(request.user, "communications.send_notification").filter(pk__in=[r.pk for r in page]).values_list("pk", flat=True))
    return render(request, "communications/history.html", {"page": page, "rows": [(r, r.pk in can_send) for r in page]})


@never_cache
@login_required(login_url="reporting:login")
@require_http_methods(["GET"])
def templates(request):
    rows = NotificationTemplate.objects.filter(company__in=queries.companies(request.user, "communications.manage_templates"))
    return render(request, "communications/templates.html", {"templates": rows})


@never_cache
@login_required(login_url="reporting:login")
@require_http_methods(["GET", "POST"])
def template_edit(request, pk=None):
    row = get_object_or_404(NotificationTemplate.objects.filter(company__in=queries.companies(request.user,
        "communications.manage_templates")), pk=pk) if pk else None
    form = TemplateForm(request.POST if request.method == "POST" else None, actor=request.user, instance=row)
    if request.method == "POST" and form.is_valid():
        try:
            services.save_template(actor=request.user, template=row, **form.cleaned_data)
        except ValidationError as error:
            form.add_error(None, " ".join(error.messages))
        else:
            return redirect("communications:templates")
    return render(request, "communications/form.html", {"form": form, "title": "Manage notification template"},
                  status=400 if request.method == "POST" else 200)


@never_cache
@login_required(login_url="reporting:login")
@require_http_methods(["GET", "POST"])
def manual(request):
    form = ManualForm(request.POST if request.method == "POST" else None, actor=request.user)
    if request.method == "POST" and form.is_valid():
        try:
            services.request_notification(actor=request.user, template=form.cleaned_data["template"],
                customer=form.cleaned_data["customer"], event_key="MANUAL:" + str(form.cleaned_data["request_key"]))
        except ValidationError as error:
            form.add_error(None, " ".join(error.messages))
        else:
            messages.success(request, "Notification queued. Dispatch is a separate authorized action.")
            return redirect("communications:history")
    return render(request, "communications/form.html", {"form": form, "title": "Queue customer message"},
                  status=400 if request.method == "POST" else 200)


@never_cache
@login_required(login_url="reporting:login")
@require_http_methods(["GET", "POST"])
def action(request, pk, operation):
    from django.http import Http404
    if operation not in ("send", "cancel"):
        raise Http404
    row = get_object_or_404(queries.history(request.user, "communications.send_notification"), pk=pk)
    form = forms.Form(request.POST if request.method == "POST" else None)
    if request.method == "POST" and form.is_valid():
        try:
            row = (services.send_notification if operation == "send" else services.cancel_notification)(actor=request.user, notification=row)
        except ValidationError as error:
            form.add_error(None, " ".join(error.messages))
        else:
            messages.info(request, "Notification status: " + row.status)
            return redirect("communications:history")
    return render(request, "communications/form.html", {"form": form, "title": operation.title() + " notification", "notification": row},
                  status=400 if request.method == "POST" else 200)
