from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.shortcuts import redirect
from django.urls import reverse
from django.views.generic import CreateView, DetailView, ListView, UpdateView

from .forms import ProjectBriefForm, WIZARD_STEPS
from .models import ProjectBrief, ProjectBriefAttachment


class ClientBriefMixin(LoginRequiredMixin):
    def get_queryset(self):
        return ProjectBrief.objects.filter(client=self.request.user)


class DashboardView(ClientBriefMixin, ListView):
    model = ProjectBrief
    template_name = "projects/dashboard.html"
    context_object_name = "briefs"
    paginate_by = 10


class ProjectBriefCreateView(LoginRequiredMixin, CreateView):
    model = ProjectBrief
    form_class = ProjectBriefForm
    template_name = "projects/brief_wizard.html"

    def get_success_url(self):
        messages.success(self.request, "Project brief submitted. We'll review it soon.")
        return reverse("projects:detail", kwargs={"pk": self.object.pk})

    def get_context_data(self, **kwargs):
        ctx = super().get_context_data(**kwargs)
        ctx["form_title"] = "Submit a Project Brief"
        ctx["submit_label"] = "Submit brief"
        ctx["wizard_steps"] = WIZARD_STEPS
        ctx["initial_step"] = self._initial_step()
        return ctx

    def _initial_step(self):
        form = self.get_form()
        if form.is_bound and form.errors:
            return form.first_error_step()
        return 1

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        if self.request.method == "POST":
            kwargs["file_list"] = self.request.FILES.getlist("attachments")
        else:
            kwargs["file_list"] = None
        return kwargs

    def form_valid(self, form):
        self.object = form.save(commit=False)
        self.object.client = self.request.user
        self.object.save()
        self._save_attachments(form)
        return redirect(self.get_success_url())

    def _save_attachments(self, form):
        for uploaded_file, original_name in form.cleaned_data.get("attachments", []):
            attachment = ProjectBriefAttachment(
                brief=self.object,
                original_filename=original_name,
            )
            attachment.file.save(original_name, uploaded_file, save=True)


class ProjectBriefDetailView(ClientBriefMixin, DetailView):
    model = ProjectBrief
    template_name = "projects/brief_detail.html"
    context_object_name = "brief"


class ProjectBriefUpdateView(ClientBriefMixin, UserPassesTestMixin, UpdateView):
    model = ProjectBrief
    form_class = ProjectBriefForm
    template_name = "projects/brief_wizard.html"

    def test_func(self):
        brief = self.get_object()
        return brief.is_editable_by_client

    def handle_no_permission(self):
        messages.error(self.request, "This brief can no longer be edited.")
        return redirect("projects:detail", pk=self.kwargs["pk"])

    def get_success_url(self):
        messages.success(self.request, "Project brief updated.")
        return reverse("projects:detail", kwargs={"pk": self.object.pk})

    def get_context_data(self, **kwargs):
        ctx = super().get_context_data(**kwargs)
        ctx["form_title"] = "Edit Project Brief"
        ctx["submit_label"] = "Save changes"
        ctx["brief"] = self.object
        ctx["wizard_steps"] = WIZARD_STEPS
        ctx["initial_step"] = self._initial_step()
        return ctx

    def _initial_step(self):
        form = self.get_form()
        if form.is_bound and form.errors:
            return form.first_error_step()
        return 1

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        if self.request.method == "POST":
            kwargs["file_list"] = self.request.FILES.getlist("attachments")
        else:
            kwargs["file_list"] = None
        return kwargs

    def form_valid(self, form):
        response = super().form_valid(form)
        self._save_attachments(form)
        return response

    def _save_attachments(self, form):
        for uploaded_file, original_name in form.cleaned_data.get("attachments", []):
            attachment = ProjectBriefAttachment(
                brief=self.object,
                original_filename=original_name,
            )
            attachment.file.save(original_name, uploaded_file, save=True)
