##############################################################################
# Copyright (c) 2016 Max Breitenfeldt and others.
# Copyright (c) 2018 Parker Berberian, Sawyer Bergeron, and others.
#
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Apache License, Version 2.0
# which accompanies this distribution, and is available at
# http://www.apache.org/licenses/LICENSE-2.0
##############################################################################

from django.contrib import messages
from django.shortcuts import get_object_or_404
from django.http import JsonResponse
from django.urls import reverse
from django.utils import timezone
from django.views import View
from django.views.generic import FormView
from django.views.generic import TemplateView
from django.shortcuts import redirect, render
import json

from booking.forms import BookingForm, BookingEditForm
from resource_inventory.models import ResourceBundle
from resource_inventory.resource_manager import ResourceManager
from booking.models import Booking, Installer, Opsys
from booking.stats import StatisticsManager


def drop_filter(context):
    installer_filter = {}
    for os in Opsys.objects.all():
        installer_filter[os.id] = []
        for installer in os.sup_installers.all():
            installer_filter[os.id].append(installer.id)

    scenario_filter = {}
    for installer in Installer.objects.all():
        scenario_filter[installer.id] = []
        for scenario in installer.sup_scenarios.all():
            scenario_filter[installer.id].append(scenario.id)

    context.update({'installer_filter': json.dumps(installer_filter), 'scenario_filter': json.dumps(scenario_filter)})


class BookingFormView(FormView):
    template_name = "booking/booking_calendar.html"
    form_class = BookingForm

    def dispatch(self, request, *args, **kwargs):
        self.resource = get_object_or_404(ResourceBundle, id=self.kwargs['resource_id'])
        return super(BookingFormView, self).dispatch(request, *args, **kwargs)

    def get_context_data(self, **kwargs):
        title = 'Booking: ' + str(self.resource.id)
        context = super(BookingFormView, self).get_context_data(**kwargs)
        context.update({'title': title, 'resource': self.resource})

        drop_filter(context)

        return context

    def get_success_url(self):
        return reverse('booking:create', kwargs=self.kwargs)

    def form_valid(self, form):
        if not self.request.user.is_authenticated:
            messages.add_message(self.request, messages.ERROR,
                                 'You need to be logged in to book a Pod.')
            return super(BookingFormView, self).form_invalid(form)

        if form.cleaned_data['end'] - form.cleaned_data['start'] > timezone.timedelta(days=21):
            messages.add_message(self.request, messages.ERROR,
                                 'Bookings can be no more than 3 weeks long.')
            return super(BookingFormView, self).form_invalid(form)

        user = self.request.user
        booking = Booking(start=form.cleaned_data['start'],
                          end=form.cleaned_data['end'],
                          purpose=form.cleaned_data['purpose'],
                          installer=form.cleaned_data['installer'],
                          scenario=form.cleaned_data['scenario'],
                          resource=self.resource,
                          owner=user
                          )
        try:
            booking.save()
        except ValueError as err:
            messages.add_message(self.request, messages.ERROR, err)
            return super(BookingFormView, self).form_invalid(form)
        messages.add_message(self.request, messages.SUCCESS, 'Booking saved')
        return super(BookingFormView, self).form_valid(form)


class BookingEditFormView(FormView):
    template_name = "booking/booking_calendar.html"
    form_class = BookingEditForm

    def is_valid(self):
        return True

    def dispatch(self, request, *args, **kwargs):
        self.resource = get_object_or_404(ResourceBundle, id=self.kwargs['resource_id'])
        self.original_booking = get_object_or_404(Booking, id=self.kwargs['booking_id'])
        return super(BookingEditFormView, self).dispatch(request, *args, **kwargs)

    def get_context_data(self, **kwargs):
        title = 'Editing Booking on: ' + self.resource.name
        context = super(BookingEditFormView, self).get_context_data(**kwargs)
        context.update({'title': title, 'resource': self.resource, 'booking': self.original_booking})

        drop_filter(context)

        return context

    def get_form_kwargs(self):
        kwargs = super(BookingEditFormView, self).get_form_kwargs()
        kwargs['purpose'] = self.original_booking.purpose
        kwargs['start'] = self.original_booking.start
        kwargs['end'] = self.original_booking.end
        return kwargs

    def get_success_url(self):
        return reverse('booking:create', args=(self.resource.id,))

    def form_valid(self, form):

        if not self.request.user.is_authenticated:
            messages.add_message(self.request, messages.ERROR,
                                 'You need to be logged in to book a Pod.')
            return super(BookingEditFormView, self).form_invalid(form)

        if not self.request.user == self.original_booking.user:
            messages.add_message(self.request, messages.ERROR,
                                 'You are not the owner of this booking.')
            return super(BookingEditFormView, self).form_invalid(form)

        # Do Conflict Checks
        if self.original_booking.end != form.cleaned_data['end']:
            if form.cleaned_data['end'] - self.original_booking.end > timezone.timedelta(days=7):
                messages.add_message(self.request, messages.ERROR,
                                     'Extensions can not be longer than one week.')
                return super(BookingEditFormView, self).form_invalid(form)
            elif self.original_booking.ext_count <= 0:
                messages.add_message(self.request, messages.ERROR,
                                     'Cannot change end date after maximum number of extensions reached.')
                return super(BookingEditFormView, self).form_invalid(form)

            else:
                self.original_booking.ext_count -= 1

        if self.original_booking.start != form.cleaned_data['start']:
            if timezone.now() > form.cleaned_data['start']:
                messages.add_message(self.request, messages.ERROR,
                                     'Cannot change start date after it has occurred.')
                return super(BookingEditFormView, self).form_invalid(form)
        self.original_booking.start = form.cleaned_data['start']
        self.original_booking.end = form.cleaned_data['end']
        self.original_booking.purpose = form.cleaned_data['purpose']
        self.original_booking.installer = form.cleaned_data['installer']
        self.original_booking.scenario = form.cleaned_data['scenario']
        self.original_booking.reset = form.cleaned_data['reset']
        try:
            self.original_booking.save()
        except ValueError as err:
            messages.add_message(self.request, messages.ERROR, err)
            return super(BookingEditFormView, self).form_invalid(form)

        return super(BookingEditFormView, self).form_valid(form)


class BookingView(TemplateView):
    template_name = "booking/booking_detail.html"

    def get_context_data(self, **kwargs):
        booking = get_object_or_404(Booking, id=self.kwargs['booking_id'])
        title = 'Booking Details'
        context = super(BookingView, self).get_context_data(**kwargs)
        context.update({'title': title, 'booking': booking})
        return context


class BookingDeleteView(TemplateView):
    template_name = "booking/booking_delete.html"

    def get_context_data(self, **kwargs):
        booking = get_object_or_404(Booking, id=self.kwargs['booking_id'])
        title = 'Delete Booking'
        context = super(BookingDeleteView, self).get_context_data(**kwargs)
        context.update({'title': title, 'booking': booking})
        return context


def bookingDelete(request, booking_id):
    booking = get_object_or_404(Booking, id=booking_id)
    booking.delete()
    messages.add_message(request, messages.SUCCESS, 'Booking deleted')
    return redirect('../../../../')


class BookingListView(TemplateView):
    template_name = "booking/booking_list.html"

    def get_context_data(self, **kwargs):
        bookings = Booking.objects.filter(end__gte=timezone.now())
        title = 'Search Booking'
        context = super(BookingListView, self).get_context_data(**kwargs)
        context.update({'title': title, 'bookings': bookings})
        return context


class ResourceBookingsJSON(View):
    def get(self, request, *args, **kwargs):
        resource = get_object_or_404(ResourceBundle, id=self.kwargs['resource_id'])
        bookings = resource.booking_set.get_queryset().values(
            'id',
            'start',
            'end',
            'purpose',
            'jira_issue_status',
            'config_bundle__name'
        )
        return JsonResponse({'bookings': list(bookings)})


def booking_detail_view(request, booking_id):
    user = None
    if request.user.is_authenticated:
        user = request.user
    else:
        return render(request, "dashboard/login.html", {'title': 'Authentication Required'})

    booking = get_object_or_404(Booking, id=booking_id)
    return render(request, "booking/booking_detail.html", {
        'title': 'Booking Details',
        'booking': booking,
        'pdf': ResourceManager().makePDF(booking.resource),
        'user_id': user.id})


def booking_stats_view(request):
    return render(
            request,
            "booking/stats.html",
            context={
                "data": StatisticsManager.getContinuousBookingTimeSeries(),
                "title": "Booking Statistics"
                }
            )


def booking_stats_json(request):
    try:
        span = int(request.GET.get("days", 14))
    except:
        span = 14
    return JsonResponse(StatisticsManager.getContinuousBookingTimeSeries(span), safe=False)