from django.shortcuts import render
from django.contrib.auth.decorators import permission_required, login_required
from django.utils.decorators import method_decorator
from django.views.decorators.http import require_http_methods
from django.views.decorators.csrf import ensure_csrf_cookie
from django.http import (
    HttpResponse,
    HttpResponseRedirect,
    JsonResponse,
    HttpResponseForbidden,
)
from django.conf import settings
from django.utils.translation import gettext as _
from django.forms.models import model_to_dict
from dal import autocomplete
from django.utils import timezone

import logging
import datetime
import html

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import authentication, permissions
from members.permissions import CheckByEmailPermission

from members.models import Member, Request, Payment
from members.forms import MemberForm, CSVValidationError
from members.tables import MemberTable

from members.views.utils import *


@ensure_csrf_cookie
@require_http_methods(["GET"])
@login_required(login_url="/admin/login")
@permission_required("members.read_member", raise_exception=True)
def member_list(request, *args, **kwargs):
    """Render members list."""
    search = request.GET.get("q", None)
    if search:
        members = Member.find_members_by_name(search)
    else:
        members = Member.objects.all()

    table = MemberTable(
        members,
        request=request,
        exclude=["id"],
        attrs={"class": "table table-bordered table-hover"},
    )

    table.paginate(page=request.GET.get("page", 1), per_page=25)
    table_html = convert_table_to_html(table, request)

    queryset = Member.get_members_with_latest_payment(members)
    # Member fee is valid from 1.9.-31.8.
    f_day = 1
    f_month = 9
    now = timezone.now()
    if now.month >= f_month:
        filter_date = timezone.make_aware(datetime.datetime(now.year, f_month, f_day))
    else:
        filter_date = timezone.make_aware(
            datetime.datetime(now.year - 1, f_month, f_day)
        )
    context = {
        "table": table_html,
        "member_count": len(members),
        "paid_count": len(queryset.filter(last_paid__gte=filter_date)),
        "notification": request.GET.get("notification", None),
    }
    return render(request, "members/member_list.html", context)


@ensure_csrf_cookie
@require_http_methods(["GET"])
@login_required(login_url="/admin/login")
@permission_required("members.add_member", raise_exception=True)
def member_add(request, *args, **kwargs):
    """Render add member page."""
    form = MemberForm()
    return render(request, "members/member_add.html", {"form": form})


@ensure_csrf_cookie
@require_http_methods(["GET"])
@login_required(login_url="/admin/login")
@permission_required("members.delete_member", raise_exception=True)
def member_delete_confirm(request, *args, **kwargs):
    """Render member deletion confirmation page."""
    i = kwargs.pop("index", None)
    if i is None:
        return error_view(request, _("No member id specified"))
    else:
        member = Member.objects.get(id=i)
        form = MemberForm(instance=member)
        return render(
            request,
            "members/member_delete_confirm.html",
            {"member_id": i, "form": form},
        )


@ensure_csrf_cookie
@require_http_methods(["GET"])
@login_required(login_url="/admin/login")
@permission_required("members.add_member", raise_exception=True)
def member_add_many(request, *args, **kwargs):
    """Render add multiple members page."""
    return render(request, "members/member_add_many.html", {})


@ensure_csrf_cookie
@require_http_methods(["POST"])
@login_required(login_url="/admin/login")
@permission_required("members.add_member", raise_exception=True)
def add_many_confirm(request, *args, **kwargs):
    models = request.session["models"]
    payment_source = request.session["payment_source"]

    try:
        members, payments = models.members, models.payments

        for member in members:
            member.save()
            if not member.payments.exists():  # create payment for new members
                payment = Payment.objects.create(member=member, source=payment_source)

        for payment in payments:
            payment.save()

        msg = "Successfully imported {} members and {} payments."
        notification = _(msg).format(len(members), len(payments))
        return HttpResponseRedirect(
            "/members/list?notification={}".format(html.escape(notification))
        )
    except Exception as ex:
        logging.exception('Failed to save models after "add many."')
        return error_view(request, _("Failed to import members"))


@ensure_csrf_cookie
@require_http_methods(["POST"])
@login_required(login_url="/admin/login")
@permission_required("members.add_member", raise_exception=True)
def member_submit(request, *args, **kwargs):
    """Add member based on data gained from member form."""
    form = MemberForm(request.POST)
    if form.is_valid():
        form.save()
        logging.info(
            "Saved new member to member register"
            "with the following info: {}".format(form.cleaned_data)
        )
        notification = "{} {} {}.".format(
            _("Successfully added member"),
            form.cleaned_data["last_name"],
            form.cleaned_data["first_name"],
        )

        return HttpResponseRedirect(
            "/members/list?notification={}".format(html.escape(notification))
        )
    else:
        return error_view(request, form.errors)


@ensure_csrf_cookie
@require_http_methods(["POST"])
@login_required(login_url="/admin/login")
@permission_required("members.change_member", raise_exception=True)
def member_update(request, *args, **kwargs):
    """Update member information."""
    id = request.POST.get("id", None)
    logging.debug(id)
    if id is not None:
        member = Member.objects.get(id=id)
    else:
        return error_view(request, _("Member missing 'id' field."))

    form = MemberForm(request.POST, instance=member)
    if form.is_valid():
        form.save()

        logging.info(
            "Updated member in member register with the following info: {}".format(form)
        )
        notification = "{} {} {}.".format(
            _("Successfully updated member"), member.last_name, member.first_name
        )
        return HttpResponseRedirect(
            "/members/list?notification={}".format(html.escape(notification))
        )
    else:
        return error_view(request, form.errors)


@ensure_csrf_cookie
@require_http_methods(["POST"])
@login_required(login_url="/admin/login")
@permission_required("members.delete_member", raise_exception=True)
def member_delete(request, *args, **kwargs):
    """Delete member."""
    try:
        id = request.POST["id"]
    except KeyError:
        return error_view(request, _("No member id specified"))

    try:
        member = Member.objects.get(id=id)
        notification = "{} {} {}.".format(
            _("Successfully deleted member"), member.last_name, member.first_name
        )
        member.delete()
        logging.info(
            "Delete member in member register with the following id: {}".format(id)
        )
        return HttpResponseRedirect(
            "/members/list?notification={}".format(html.escape(notification))
        )
    except:
        return error_view(request, _("Could not delete member object"))


@ensure_csrf_cookie
@require_http_methods(["GET"])
@login_required(login_url="/admin/login")
@permission_required("members.change_member", raise_exception=True)
def member_edit(request, *args, **kwargs):
    """Edit member information."""
    i = kwargs.pop("index", None)
    if i is None:
        return error_view(request, _("No member id specified"))
    else:
        member = Member.objects.get(id=i)
        form = MemberForm(instance=member)
        return render(
            request, "members/member_edit.html", {"member_id": i, "form": form}
        )


@method_decorator(login_required(login_url="/admin/login"), name="dispatch")
@method_decorator(permission_required("members.change_member"), name="dispatch")
class MemberAutoComplete(autocomplete.Select2QuerySetView):
    def get_queryset(self):
        qs = Member.objects.all()

        if self.q:
            qs = Member.find_members_by_name(self.q)

        return qs.order_by("last_name")


class CheckByEmail(APIView):
    """Check by email"""

    authentication_classes = (authentication.TokenAuthentication,)
    permission_classes = (CheckByEmailPermission,)

    def get(self, request, format=None):
        email = request.query_params.get("email")
        exists = bool(email and Member.objects.filter(email=email).exists())
        resp = {"exists": exists}
        return JsonResponse(resp)
