from django.urls import reverse_lazy
from django.http import HttpResponseRedirect
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import (View, TemplateView, ListView, CreateView,
                                  DetailView)
from django.views.generic.detail import SingleObjectMixin
from django.contrib import messages
from django.shortcuts import get_object_or_404
from rules.contrib.views import PermissionRequiredMixin

from .models import Job, Application, Question
from .forms import JobForm, QuestionFormSet, ApplicationForm, AnswerForm


class Index(TemplateView):
    template_name = 'jobs/index.html'

    def get_context_data(self, *args, **kwargs):
        context = super().get_context_data(*args, **kwargs)
        context['jobs'] = Job.objects.all().order_by('-updated')[:6]
        return context


class JobList(ListView):
    context_object_name = 'jobs'
    model = Job


class JobDetail(DetailView):
    context_object_name = 'job'
    model = Job


class JobRenew(LoginRequiredMixin, PermissionRequiredMixin, SingleObjectMixin,
               View):
    model = Job
    permission_required = 'jobs.change_job'
    http_method_names = ['post']

    def post(self, request, *args, **kwargs):
        job = self.get_object()
        job.renew()
        messages.add_message(
            request, messages.SUCCESS, 'Job has been renewed until {}.'.format(
                job.expires.isoformat(' ', 'seconds')))
        return HttpResponseRedirect(job.get_absolute_url())


class JobCreate(LoginRequiredMixin, CreateView):
    model = Job
    form_class = JobForm
    success_url = reverse_lazy("jobs:job_list")

    def get(self, request, *args, **kwargs):
        self.object = None
        form = self.get_form(self.get_form_class())
        question_form = QuestionFormSet()
        return self.render_to_response(
            self.get_context_data(form=form, question_form=question_form))

    def post(self, request, *args, **kwargs):
        self.object = None
        form_class = self.get_form_class()
        form = self.get_form(form_class)
        question_form = QuestionFormSet(self.request.POST)
        if (form.is_valid() and question_form.is_valid()):
            return self.form_valid(form, question_form)
        else:
            return self.form_invalid(form, question_form)

    def form_valid(self, form, question_form):
        self.object = form.save(commit=False)
        self.object.posted_by = self.request.user
        self.object.save()
        form.save_m2m()

        question_form.instance = self.object
        question_form.save()

        return HttpResponseRedirect(self.get_success_url())

    def form_invalid(self, form, question_form):
        return self.render_to_response(
            self.get_context_data(form=form, question_form=question_form))


class ApplicationCreate(LoginRequiredMixin, CreateView):
    # TODO: restrict users from re-application
    model = Application
    form_class = ApplicationForm
    success_url = reverse_lazy("jobs:job_list")

    def get_question_queryset(self):
        # filter questions for particular job and order it so same queryset
        # can be used stably as initial params for GET and POST requests
        return Question.objects.filter(
            job_id=self.kwargs['job_pk']).order_by('id')

    def get_answer_formset(self, *args):
        questions = self.get_question_queryset()
        return AnswerForm.inlineformset_factory(extra=questions.count())(
            initial=[{
                'question': q.id
            } for q in questions], *args)

    def get(self, request, *args, **kwargs):
        self.object = None
        form = self.get_form(self.get_form_class())
        answer_form = self.get_answer_formset()
        return self.render_to_response(
            self.get_context_data(form=form, answer_form=answer_form))

    def post(self, request, *args, **kwargs):
        self.object = None
        form_class = self.get_form_class()
        form = self.get_form(form_class)
        answer_form = self.get_answer_formset(self.request.POST)
        if (form.is_valid() and answer_form.is_valid()):
            return self.form_valid(form, answer_form)
        else:
            return self.form_invalid(form, answer_form)

    def form_valid(self, form, answer_form):
        self.object = form.save(commit=False)
        self.object.applicant = self.request.user
        self.object.job = get_object_or_404(Job, id=self.kwargs['job_pk'])
        self.object.save()
        form.save_m2m()

        answer_form.instance = self.object
        answer_form.save()

        messages.add_message(
            self.request, messages.SUCCESS,
            'Your application has been succesfully received.')

        return HttpResponseRedirect(self.get_success_url())

    def form_invalid(self, form, answer_form):
        return self.render_to_response(
            self.get_context_data(form=form, answer_form=answer_form))


class ApplicationList(LoginRequiredMixin, PermissionRequiredMixin, ListView):
    model = Application
    context_object_name = 'applications'
    permission_required = 'jobs.change_job'

    def get_permission_object(self):
        return get_object_or_404(Job, id=self.kwargs['job_pk'])

    def get_queryset(self):
        return super().get_queryset().filter(job_id=self.kwargs['job_pk'])


class ApplicationDetail(LoginRequiredMixin, DetailView):
    model = Application