from datetime import timedelta
from django.shortcuts import render, redirect
from django.urls import reverse
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseNotFound, Http404
from django.views.decorators.csrf import csrf_exempt
from django.utils import timezone
from django.contrib import messages
from django.utils.translation import ugettext_lazy as _

from .forms import NewPaymentForm
from .models import Payment, Subscription, BACKENDS, ACTIVE_BACKENDS, Feedback


def require_backend(name):
    backend = BACKENDS.get(name)
    if not backend:
        raise Http404()
    if not backend.backend_enabled:
        raise Http404()
    return backend


@login_required
def new(request):
    if request.method != 'POST':
        return redirect('account:index')

    if Payment.objects.filter(user=request.user, status='new').count() > 10:
        messages.error(request, "Too many open payments.")
        return redirect('account:index')

    form = NewPaymentForm(request.POST)

    if not form.is_valid():
        return redirect('account:index')

    if request.user.vpnuser.get_subscription() is not None:
        return redirect('account:index')

    subscr = form.cleaned_data['subscr'] == '1'
    backend_id = form.cleaned_data['method']
    months = int(form.cleaned_data['time'])

    if backend_id not in ACTIVE_BACKENDS:
        return HttpResponseNotFound()

    if subscr:
        if months not in (3, 6, 12):
            return redirect('account:index')

        rps = Subscription(
            user=request.user,
            backend_id=backend_id,
            period=str(months) + 'm',
        )
        rps.save()

        r = rps.backend.new_subscription(rps)

    else:
        payment = Payment.create_payment(backend_id, request.user, months)
        payment.save()

        r = payment.backend.new_payment(payment)

    if not r:
        payment.status = 'error'
        payment.save()
        raise Exception("Failed to initialize payment #%d" % payment.id)

    if isinstance(r, str):
        return render(request, 'payments/form.html', dict(html=r))
    elif r is None:
        return redirect('payments:view', payment.id)

    return r

def plain_callback(backend_name, method='callback'):
    @csrf_exempt
    def callback(request):
        backend = require_backend(backend_name)

        m = getattr(backend, method)
        if m and m(Payment, request):
            return HttpResponse()
        else:
            return HttpResponseBadRequest()

    return callback

def payment_callback(backend_name):
    @csrf_exempt
    def callback(request, id):
        backend = require_backend(backend_name)
        p = Payment.objects.get(id=id)

        if backend.callback(p, request):
            return HttpResponse()
        else:
            return HttpResponseBadRequest()

    return callback

def sub_callback(backend_name):
    @csrf_exempt
    def callback(request, id):
        backend = require_backend(backend_name)

        p = Subscription.objects.get(id=id)

        if backend.callback_subscr(p, request):
            return HttpResponse()
        else:
            return HttpResponseBadRequest()

    return callback

@csrf_exempt
def stripe_hook(request):
    backend = require_backend('stripe')

    if backend.webhook(request):
        return HttpResponse()
    else:
        return HttpResponseBadRequest()


@login_required
@csrf_exempt
def view(request, id):
    p = Payment.objects.get(id=id, user=request.user)
    return render(request, 'payments/view.html', dict(payment=p))


@login_required
def cancel(request, id):
    p = Payment.objects.get(id=id, user=request.user)
    if p.status == 'new':
        p.status = 'cancelled'
        p.save()
    return render(request, 'payments/view.html', dict(payment=p))


@login_required
def cancel_subscr(request, id=None):
    if request.method == 'POST' and id:
        p = Subscription.objects.get(id=id, user=request.user)

        # Saving any feedback note
        feedback = request.POST.get('feedback')
        if feedback:
            feedback = feedback[:10000]
            f = Feedback(user=request.user, subscription=p, message=feedback)
            f.save()

        try:
            if p.backend.cancel_subscription(p):
                messages.add_message(request, messages.INFO, _("Subscription cancelled!"))
            else:
                messages.add_message(request, messages.ERROR, _("Could not cancel the subscription. It may have already been cancelled or caused an error."))
        except NotImplementedError:
            pass
        return redirect('account:index')

    subscription = request.user.vpnuser.get_subscription(include_unconfirmed=True)
    return render(request, 'payments/cancel_subscr.html', {
        'subscription': subscription,
    })


@login_required
def return_subscr(request, id):
    p = Subscription.objects.get(id=id, user=request.user)
    if p.status == 'new':
        p.status = 'unconfirmed'
        p.save()
    return redirect('account:index')


@login_required
def list_payments(request):
    # Only show recent cancelled payments
    cancelled_limit = timezone.now() - timedelta(days=3)

    objects = request.user.payment_set.exclude(status='cancelled',
                                               created__lte=cancelled_limit)
    return render(request, 'payments/list.html', dict(payments=objects))
