#
# Copyright 2016,2017
# - Skia <skia@libskia.so>
# - Sli <antoine@bartuccio.fr>
#
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# http://ae.utbm.fr.
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License a published by the Free Software
# Foundation; either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
# Place - Suite 330, Boston, MA 02111-1307, USA.
#
#

from __future__ import annotations

import csv
import itertools
from typing import TYPE_CHECKING, Any

from django.contrib.auth.mixins import (
    LoginRequiredMixin,
    PermissionRequiredMixin,
    UserPassesTestMixin,
)
from django.contrib.messages.views import SuccessMessageMixin
from django.core.exceptions import NON_FIELD_ERRORS, PermissionDenied, ValidationError
from django.core.paginator import InvalidPage, Paginator
from django.db.models import F, Prefetch, Q, Sum
from django.db.models.functions import Length
from django.http import Http404, StreamingHttpResponse
from django.shortcuts import get_object_or_404, redirect
from django.urls import reverse, reverse_lazy
from django.utils import timezone
from django.utils.functional import cached_property
from django.utils.timezone import now
from django.utils.translation import gettext
from django.utils.translation import gettext_lazy as _
from django.views.generic import DetailView, ListView, View
from django.views.generic.detail import SingleObjectMixin
from django.views.generic.edit import CreateView, DeleteView, FormMixin, UpdateView

from club.forms import (
    ClubAddMemberForm,
    ClubAdminEditForm,
    ClubEditForm,
    ClubOldMemberForm,
    ClubRoleCreateForm,
    ClubRoleFormSet,
    ClubSearchForm,
    JoinClubForm,
    MailingForm,
    SellingsForm,
)
from club.models import (
    Club,
    ClubLink,
    ClubRole,
    LinkType,
    Mailing,
    MailingSubscription,
    Membership,
)
from com.models import Poster
from com.views import (
    PosterCreateBaseView,
    PosterDeleteBaseView,
    PosterEditBaseView,
    PosterListBaseView,
)
from core.auth.mixins import CanEditMixin, PermissionOrClubBoardRequiredMixin
from core.models import Page, PageRev
from core.views import BasePageEditView, DetailFormView, UseFragmentsMixin
from core.views.mixins import (
    AllowFragment,
    FragmentMixin,
    FragmentRenderer,
    TabedViewMixin,
)
from counter.models import Selling

if TYPE_CHECKING:
    from django.utils.safestring import SafeString


class ClubTabsMixin(TabedViewMixin):
    def get_tabs_title(self):
        if not hasattr(self, "object") or not self.object:
            self.object = self.get_object()
        if isinstance(self.object, PageRev):
            self.object = self.object.page.club
        elif isinstance(self.object, Poster):
            self.object = self.object.club
        elif hasattr(self, "club"):
            self.object = self.club
        return self.object.get_display_name()

    def get_list_of_tabs(self):
        tab_list = [
            {
                "url": reverse("club:club_view", kwargs={"club_id": self.object.id}),
                "slug": "infos",
                "name": _("Infos"),
            }
        ]
        if self.request.user.has_perm("club.view_club"):
            tab_list.extend(
                [
                    {
                        "url": reverse(
                            "club:club_members", kwargs={"club_id": self.object.id}
                        ),
                        "slug": "members",
                        "name": _("Members"),
                    },
                    {
                        "url": reverse(
                            "club:club_old_members", kwargs={"club_id": self.object.id}
                        ),
                        "slug": "elderlies",
                        "name": _("Old members"),
                    },
                ]
            )
            if self.object.page:
                tab_list.append(
                    {
                        "url": reverse(
                            "club:club_hist", kwargs={"club_id": self.object.id}
                        ),
                        "slug": "history",
                        "name": _("History"),
                    }
                )
        if self.request.user.can_edit(self.object):
            tab_list.extend(
                [
                    {
                        "url": reverse(
                            "club:tools", kwargs={"club_id": self.object.id}
                        ),
                        "slug": "tools",
                        "name": _("Tools"),
                    },
                    {
                        "url": reverse(
                            "club:club_edit", kwargs={"club_id": self.object.id}
                        ),
                        "slug": "edit",
                        "name": _("Edit"),
                    },
                ]
            )
            if self.object.page and self.request.user.can_edit(self.object.page):
                tab_list.append(
                    {
                        "url": reverse(
                            "core:page_edit",
                            kwargs={"page_name": self.object.page.get_full_name()},
                        ),
                        "slug": "page_edit",
                        "name": _("Edit club page"),
                    }
                )
            tab_list.extend(
                [
                    {
                        "url": reverse(
                            "club:club_sellings", kwargs={"club_id": self.object.id}
                        ),
                        "slug": "sellings",
                        "name": _("Sellings"),
                    },
                    {
                        "url": reverse(
                            "club:mailing", kwargs={"club_id": self.object.id}
                        ),
                        "slug": "mailing",
                        "name": _("Mailing list"),
                    },
                    {
                        "url": reverse(
                            "club:poster_list", kwargs={"club_id": self.object.id}
                        ),
                        "slug": "posters",
                        "name": _("Posters"),
                    },
                ]
            )
        return tab_list


class ClubListView(AllowFragment, FormMixin, ListView):
    """List the clubs of the AE, with a form to perform basic search.

    Notes:
        This view is fully public, because we want to advertise as much as possible
        the cultural life of the AE.
        In accordance with that matter, searching and listing the clubs is done
        entirely server-side (no AlpineJS involved) ;
        this is done this way in order to be sure the page is the most accessible
        and SEO-friendly possible, even if it makes the UX slightly less smooth.
    """

    template_name = "club/club_list.jinja"
    form_class = ClubSearchForm
    queryset = Club.objects.prefetch_related(
        Prefetch("links", queryset=ClubLink.objects.select_related("link_type"))
    ).order_by("name")
    paginate_by = 20

    def get_form_kwargs(self):
        res = super().get_form_kwargs()
        # if request.GET is empty, the form will interpret club_status as None,
        # even though we want it to be initially True,
        # so we force a defaut True value.
        res["data"] = {"club_status": True} | self.request.GET.dict()
        return res

    def get_queryset(self):
        form: ClubSearchForm = self.get_form()
        qs = self.queryset
        if not form.is_valid():
            return qs.none()
        if name := form.cleaned_data.get("name"):
            qs = qs.filter(name__icontains=name)
        if (is_active := form.cleaned_data.get("club_status")) is not None:
            qs = qs.filter(is_active=is_active)
        return qs


class ClubView(ClubTabsMixin, DetailView):
    """Front page of a Club."""

    model = Club
    pk_url_kwarg = "club_id"
    template_name = "club/club_detail.jinja"
    current_tab = "infos"

    def get_context_data(self, **kwargs):
        kwargs = super().get_context_data(**kwargs)
        kwargs["page_revision"] = (
            PageRev.objects.filter(page_id=self.object.page_id)
            .order_by("-date")
            .values_list("content", flat=True)
            .first()
        )
        kwargs["links"] = list(self.object.links.select_related("link_type").all())
        return kwargs


class ClubRevView(LoginRequiredMixin, ClubView):
    """Display a specific page revision."""

    def dispatch(self, request, *args, **kwargs):
        obj = self.get_object()
        self.revision = get_object_or_404(PageRev, pk=kwargs["rev_id"], page__club=obj)
        return super().dispatch(request, *args, **kwargs)

    def get_context_data(self, **kwargs):
        kwargs = super().get_context_data(**kwargs)
        kwargs["page_revision"] = self.revision.content
        return kwargs


class ClubPageEditView(ClubTabsMixin, BasePageEditView):
    template_name = "club/pagerev_edit.jinja"
    current_tab = "page_edit"

    @cached_property
    def club(self):
        return get_object_or_404(Club, pk=self.kwargs["club_id"])

    @cached_property
    def page(self) -> Page:
        page = self.club.page
        page.set_lock(self.request.user)
        return page

    def get_success_url(self, **kwargs):
        return reverse_lazy("club:club_view", kwargs={"club_id": self.club.id})


class ClubPageHistView(ClubTabsMixin, PermissionRequiredMixin, DetailView):
    """Modification history of the page."""

    model = Club
    pk_url_kwarg = "club_id"
    template_name = "club/page_history.jinja"
    current_tab = "history"
    permission_required = "club.view_club"


class ClubToolsView(ClubTabsMixin, CanEditMixin, DetailView):
    """Tools page of a Club."""

    model = Club
    pk_url_kwarg = "club_id"
    template_name = "club/club_tools.jinja"
    current_tab = "tools"


class ClubAddMembersFragment(
    FragmentMixin, PermissionRequiredMixin, SuccessMessageMixin, CreateView
):
    template_name = "club/fragments/add_member.jinja"
    model = Membership
    object = None
    reload_on_redirect = True
    permission_required = "club.view_club"

    def dispatch(self, *args, **kwargs):
        self.club = get_object_or_404(Club, pk=kwargs.get("club_id"))
        return super().dispatch(*args, **kwargs)

    def get_form_class(self):
        user = self.request.user
        if user.has_perm("club.add_membership") or self.club.get_membership_for(user):
            return ClubAddMemberForm
        return JoinClubForm

    def get_form_kwargs(self):
        return super().get_form_kwargs() | {
            "request_user": self.request.user,
            "club": self.club,
        }

    def render_fragment(self, request, **kwargs) -> SafeString:
        self.club = kwargs.get("club")
        return super().render_fragment(request, **kwargs)

    def get_success_url(self):
        return reverse("club:club_members", kwargs={"club_id": self.club.id})

    def get_context_data(self, **kwargs):
        return super().get_context_data(**kwargs) | {"club": self.club}

    def get_success_message(self, cleaned_data):
        if "user" not in cleaned_data or cleaned_data["user"] == self.request.user:
            return _("You are now a member of this club.")
        return _("%(user)s has been added to club.") % cleaned_data


class ClubMembersView(
    ClubTabsMixin, UseFragmentsMixin, PermissionRequiredMixin, DetailFormView
):
    """View of a club's members."""

    model = Club
    pk_url_kwarg = "club_id"
    form_class = ClubOldMemberForm
    template_name = "club/club_members.jinja"
    current_tab = "members"
    permission_required = "club.view_club"

    def get_fragments(self) -> dict[str, type[FragmentMixin] | FragmentRenderer]:
        membership = self.object.get_membership_for(self.request.user)
        if (
            membership
            and not membership.role.is_board
            and not self.request.user.has_perm("club.add_membership")
        ):
            # Simple club members won't see the form anymore.
            # Even if they saw it, they couldn't add anyone to the club anyway
            return {}
        return {"add_member_fragment": ClubAddMembersFragment}

    def get_fragment_data(self) -> dict[str, Any]:
        return {"add_member_fragment": {"club": self.object}}

    def get_form_kwargs(self):
        return super().get_form_kwargs() | {
            "user": self.request.user,
            "club": self.object,
        }

    def get_context_data(self, **kwargs):
        kwargs = super().get_context_data(**kwargs)
        editable = list(
            kwargs["form"].fields["members_old"].queryset.values_list("id", flat=True)
        )
        kwargs["members"] = list(
            self.object.members.ongoing()
            .annotate(is_editable=Q(id__in=editable))
            .order_by("role__order")
            .select_related("user", "role")
        )
        kwargs["can_end_membership"] = len(editable) > 0
        return kwargs

    def form_valid(self, form):
        for membership in form.cleaned_data.get("members_old"):
            membership.end_date = now()
            membership.save()
        return super().form_valid(form)

    def get_success_url(self, **kwargs):
        return self.request.path


class ClubOldMembersView(ClubTabsMixin, PermissionRequiredMixin, DetailView):
    """Old members of a club."""

    model = Club
    pk_url_kwarg = "club_id"
    template_name = "club/club_old_members.jinja"
    current_tab = "elderlies"
    permission_required = "club.view_club"

    def get_context_data(self, **kwargs):
        return super().get_context_data(**kwargs) | {
            "old_members": (
                self.object.members.exclude(end_date=None)
                .order_by("role__order", "description", "-end_date")
                .select_related("user", "role")
            )
        }


class ClubRoleUpdateView(
    ClubTabsMixin, UserPassesTestMixin, SuccessMessageMixin, UpdateView
):
    form_class = ClubRoleFormSet
    model = Club
    template_name = "club/club_roles.jinja"
    pk_url_kwarg = "club_id"
    current_tab = "members"
    success_message = _("Club roles updated")

    @cached_property
    def club(self) -> Club:
        return self.get_object()

    def test_func(self):
        return self.club.can_roles_be_edited_by(self.request.user)

    def get_form_kwargs(self):
        return super().get_form_kwargs() | {"form_kwargs": {"label_suffix": ""}}

    def get_success_url(self):
        return reverse("club:club_members", kwargs={"club_id": self.club.id})

    def get_context_data(self, **kwargs):
        return super().get_context_data(**kwargs) | {
            "user_role": ClubRole.objects.filter(
                club=self.club,
                members__user=self.request.user,
                members__end_date=None,
            )
            .values_list("id", flat=True)
            .first()
        }


class ClubRoleBaseCreateView(UserPassesTestMixin, SuccessMessageMixin, CreateView):
    """View to create a new Club Role, using [][club.forms.ClubRoleCreateForm].

    This view isn't meant to be called directly, but rather subclassed for each
    type of role that can exist :

    - `[ClubRolePresidencyCreateView][club.views.ClubRolePresidencyCreateView]`
      to create a presidency role
    - `[ClubRoleBoardCreateView][club.views.ClubRoleBoardCreateView]`
      to create a board role
    - `[ClubRoleMemberCreateView][club.views.ClubRoleMemberCreateView]`
      to create a member role

    Each subclass have to override the following variables :

    - `is_presidency` and `is_board`, indicating what type of role
      the view creates.
    - `role_description`, which is the title of the page, indication
       the user what kind of role is being created.

    This way, we are making sure the correct type of role will
    be created, without bothering the user with the implementation details.
    """

    form_class = ClubRoleCreateForm
    model = ClubRole
    template_name = "core/create.jinja"
    success_message = _("Role %(name)s created")
    role_description = ""
    is_presidency: bool
    is_board: bool

    @cached_property
    def club(self):
        return get_object_or_404(Club, id=self.kwargs["club_id"])

    def test_func(self):
        return self.request.user.is_authenticated and (
            self.request.user.has_perm("club.add_clubrole")
            or self.club.members.filter(
                user=self.request.user, role__is_presidency=True
            ).exists()
        )

    def get_form_kwargs(self):
        return super().get_form_kwargs() | {
            "club": self.club,
            "is_presidency": self.is_presidency,
            "is_board": self.is_board,
        }

    def get_context_data(self, **kwargs):
        return super().get_context_data(**kwargs) | {
            "object_name": self.role_description
        }

    def get_success_url(self):
        return reverse("club:club_roles", kwargs={"club_id": self.club.id})


class ClubRolePresidencyCreateView(ClubRoleBaseCreateView):
    is_presidency = True
    is_board = True
    role_description = _("club role \u2013 presidency")


class ClubRoleBoardCreateView(ClubRoleBaseCreateView):
    is_presidency = False
    is_board = True
    role_description = _("club role \u2013 board")


class ClubRoleMemberCreateView(ClubRoleBaseCreateView):
    is_presidency = False
    is_board = False
    role_description = _("club role \u2013 member")


class ClubSellingView(ClubTabsMixin, CanEditMixin, DetailFormView):
    """Sales of a club."""

    model = Club
    pk_url_kwarg = "club_id"
    template_name = "club/club_sellings.jinja"
    current_tab = "sellings"
    form_class = SellingsForm
    paginate_by = 70

    def dispatch(self, request, *args, **kwargs):
        try:
            self.asked_page = int(request.GET.get("page", 1))
        except ValueError as e:
            raise Http404 from e
        return super().dispatch(request, *args, **kwargs)

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs["club"] = self.object
        return kwargs

    def post(self, request, *args, **kwargs):
        return self.get(request, *args, **kwargs)

    def get_context_data(self, **kwargs):
        kwargs = super().get_context_data(**kwargs)

        kwargs["result"] = Selling.objects.none()
        kwargs["total"] = 0
        kwargs["total_quantity"] = 0
        kwargs["benefit"] = 0

        form: SellingsForm = self.get_form()
        if form.is_valid() and any(v for v in form.cleaned_data.values()):
            filters = form.to_filter_schema()
            qs = filters.filter(Selling.objects.filter(club=self.object))
            kwargs["total"] = qs.annotate(
                price=F("quantity") * F("unit_price")
            ).aggregate(total=Sum("price", default=0))["total"]
            kwargs["result"] = qs.select_related(
                "counter", "counter__club", "customer", "customer__user", "seller"
            ).order_by("-id")
            kwargs["total_quantity"] = qs.aggregate(total=Sum("quantity", default=0))[
                "total"
            ]
            kwargs["benefit"] = qs.exclude(product=None).aggregate(
                res=Sum("product__purchase_price", default=0)
            )["res"]

        kwargs["paginator"] = Paginator(kwargs["result"], self.paginate_by)
        try:
            kwargs["paginated_result"] = kwargs["paginator"].page(self.asked_page)
        except InvalidPage as e:
            raise Http404 from e

        return kwargs


class ClubSellingCSVView(ClubSellingView):
    """Generate sellings in csv for a given period."""

    class StreamWriter:
        """Implements a file-like interface for streaming the CSV."""

        def write(self, value):
            """Write the value by returning it, instead of storing in a buffer."""
            return value

    def write_selling(self, selling):
        row = [selling.date, selling.counter]
        if selling.seller:
            row.append(selling.seller.get_display_name())
        else:
            row.append("")
        if selling.customer:
            row.append(selling.customer.user.get_display_name())
        else:
            row.append("")
        row = [
            *row,
            selling.label,
            selling.quantity,
            selling.unit_price,
            selling.quantity * selling.unit_price,
            selling.get_payment_method_display(),
        ]
        if selling.product:
            row.append(selling.product.purchase_price)
            row.append(selling.unit_price - selling.product.purchase_price)
        else:
            row = [*row, "", ""]
        return row

    def get(self, request, *args, **kwargs):
        self.object = self.get_object()
        kwargs = self.get_context_data(**kwargs)

        # Use the StreamWriter class instead of request for streaming
        writer = csv.writer(self.StreamWriter())

        first_rows = [
            [gettext("Quantity"), kwargs["total_quantity"]],
            [gettext("Total"), kwargs["total"]],
            [gettext("Benefit"), kwargs["benefit"]],
            [
                gettext("Date"),
                gettext("Counter"),
                gettext("Barman"),
                gettext("Customer"),
                gettext("Label"),
                gettext("Quantity"),
                gettext("Unit price"),
                gettext("Total"),
                gettext("Payment method"),
                gettext("Purchase price"),
                gettext("Benefit"),
            ],
        ]

        # Stream response
        response = StreamingHttpResponse(
            itertools.chain(
                (writer.writerow(r) for r in first_rows),
                (
                    writer.writerow(self.write_selling(selling))
                    for selling in kwargs["result"]
                ),
            ),
            content_type="text/csv",
        )
        name = f"{gettext('Sellings')}_{self.object.name}.csv"
        response["Content-Disposition"] = f"attachment; filename={name}"

        return response


class ClubEditView(ClubTabsMixin, CanEditMixin, UpdateView):
    """Edit a Club.

    Regular club board members will be able to edit the main infos
    (like the logo and the description).
    Admins will also be able to edit the club properties
    (like the name and the parent club).
    """

    model = Club
    pk_url_kwarg = "club_id"
    template_name = "club/edit_club.jinja"
    current_tab = "edit"

    def get_form_class(self):
        if self.object.is_owned_by(self.request.user):
            return ClubAdminEditForm
        return ClubEditForm

    def get_context_data(self, **kwargs):
        return super().get_context_data(**kwargs) | {
            "link_types": list(LinkType.objects.order_by(Length("url_base").desc()))
        }


class ClubCreateView(PermissionRequiredMixin, CreateView):
    """Create a club (for the Sith admin)."""

    model = Club
    pk_url_kwarg = "club_id"
    fields = ["name", "parent"]
    template_name = "core/create.jinja"
    permission_required = "club.add_club"

    def form_valid(self, form):
        res = super().form_valid(form)
        self.object.create_default_roles()
        return res


class MembershipSetOldView(CanEditMixin, SingleObjectMixin, View):
    """Set a membership as being old."""

    model = Membership
    pk_url_kwarg = "membership_id"

    def post(self, *_args, **_kwargs):
        self.object = self.get_object()
        self.object.end_date = timezone.now()
        self.object.save()
        return redirect("core:user_clubs", user_id=self.object.user_id)


class MembershipDeleteView(PermissionRequiredMixin, DeleteView):
    """Delete a membership (for admins only)."""

    model = Membership
    pk_url_kwarg = "membership_id"
    template_name = "core/delete_confirm.jinja"
    permission_required = "club.delete_membership"

    def get_success_url(self):
        return reverse_lazy("core:user_clubs", kwargs={"user_id": self.object.user_id})


class ClubMailingView(ClubTabsMixin, CanEditMixin, DetailFormView):
    """A list of mailing for a given club."""

    model = Club
    form_class = MailingForm
    pk_url_kwarg = "club_id"
    template_name = "club/mailing.jinja"
    current_tab = "mailing"

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs["club_id"] = self.object.id
        kwargs["user_id"] = self.request.user.id
        kwargs["mailings"] = self.object.mailings.all()
        return kwargs

    def get_context_data(self, **kwargs):
        kwargs = super().get_context_data(**kwargs)
        mailings = list(self.object.mailings.all())
        kwargs["club"] = self.object
        kwargs["user"] = self.request.user
        kwargs["mailings"] = mailings
        kwargs["mailings_moderated"] = [m for m in mailings if m.is_moderated]
        kwargs["mailings_not_moderated"] = [m for m in mailings if not m.is_moderated]
        kwargs["form_actions"] = {
            "NEW_MALING": self.form_class.ACTION_NEW_MAILING,
            "NEW_SUBSCRIPTION": self.form_class.ACTION_NEW_SUBSCRIPTION,
            "REMOVE_SUBSCRIPTION": self.form_class.ACTION_REMOVE_SUBSCRIPTION,
        }
        return kwargs

    def add_new_mailing(self, cleaned_data) -> ValidationError | None:
        """Create a new mailing list from the form."""
        mailing = Mailing(
            club=self.object,
            email=cleaned_data["mailing_email"],
            moderator=self.request.user,
            is_moderated=False,
        )
        try:
            mailing.clean()
        except ValidationError as validation_error:
            return validation_error
        mailing.save()
        return None

    def add_new_subscription(self, cleaned_data) -> ValidationError | None:
        """Add mailing subscriptions for each user given and/or for the specified email in form."""
        users_to_save = []

        for user in cleaned_data["subscription_users"]:
            sub = MailingSubscription(
                mailing=cleaned_data["subscription_mailing"], user=user
            )
            try:
                sub.clean()
            except ValidationError as validation_error:
                return validation_error

            sub.save()
            users_to_save.append(sub)

        if cleaned_data["subscription_email"]:
            sub = MailingSubscription(
                mailing=cleaned_data["subscription_mailing"],
                email=cleaned_data["subscription_email"],
            )

        try:
            sub.clean()
        except ValidationError as validation_error:
            return validation_error
        sub.save()

        # Save users after we are sure there is no error
        for user in users_to_save:
            user.save()

        return None

    def remove_subscription(self, cleaned_data):
        """Remove specified users from a mailing list."""
        fields = [
            val for key, val in cleaned_data.items() if key.startswith("removal_")
        ]
        for field in fields:
            for sub in field:
                sub.delete()

    def form_valid(self, form):
        resp = super().form_valid(form)

        cleaned_data = form.clean()
        error = None

        if cleaned_data["action"] == self.form_class.ACTION_NEW_MAILING:
            error = self.add_new_mailing(cleaned_data)

        if cleaned_data["action"] == self.form_class.ACTION_NEW_SUBSCRIPTION:
            error = self.add_new_subscription(cleaned_data)

        if cleaned_data["action"] == self.form_class.ACTION_REMOVE_SUBSCRIPTION:
            self.remove_subscription(cleaned_data)

        if error:
            form.add_error(NON_FIELD_ERRORS, error)
            return self.form_invalid(form)

        return resp

    def get_success_url(self, **kwargs):
        return reverse("club:mailing", kwargs={"club_id": self.object.id})


class MailingDeleteView(CanEditMixin, DeleteView):
    model = Mailing
    template_name = "core/delete_confirm.jinja"
    pk_url_kwarg = "mailing_id"
    redirect_page = None

    def dispatch(self, request, *args, **kwargs):
        self.club_id = self.get_object().club.id
        return super().dispatch(request, *args, **kwargs)

    def get_success_url(self, **kwargs):
        if self.redirect_page:
            return reverse_lazy(self.redirect_page)
        else:
            return reverse_lazy("club:mailing", kwargs={"club_id": self.club_id})


class MailingSubscriptionDeleteView(CanEditMixin, DeleteView):
    model = MailingSubscription
    template_name = "core/delete_confirm.jinja"
    pk_url_kwarg = "mailing_subscription_id"

    def dispatch(self, request, *args, **kwargs):
        self.club_id = self.get_object().mailing.club.id
        return super().dispatch(request, *args, **kwargs)

    def get_success_url(self, **kwargs):
        return reverse_lazy("club:mailing", kwargs={"club_id": self.club_id})


class MailingAutoGenerationView(View):
    def dispatch(self, request, *args, **kwargs):
        self.mailing = get_object_or_404(Mailing, pk=kwargs["mailing_id"])
        if not request.user.can_edit(self.mailing):
            raise PermissionDenied
        return super().dispatch(request, *args, **kwargs)

    def get(self, request, *args, **kwargs):
        club = self.mailing.club
        self.mailing.subscriptions.all().delete()
        members = club.members.ongoing().filter(role__is_board=True)
        for member in members.all():
            MailingSubscription(user=member.user, mailing=self.mailing).save()
        return redirect("club:mailing", club_id=club.id)


class PosterListView(
    PermissionOrClubBoardRequiredMixin, ClubTabsMixin, PosterListBaseView
):
    """List communication posters."""

    current_tab = "posters"
    permission_required = "com.view_poster"

    def get_queryset(self):
        return super().get_queryset().filter(club=self.club.id)

    def get_object(self):
        return self.club

    def get_context_data(self, **kwargs):
        return super().get_context_data(**kwargs) | {
            "create_url": reverse_lazy(
                "club:poster_create", kwargs={"club_id": self.club.id}
            ),
            "get_edit_url": lambda poster: reverse(
                "club:poster_edit",
                kwargs={"club_id": self.club.id, "poster_id": poster.id},
            ),
        }


class PosterCreateView(ClubTabsMixin, PosterCreateBaseView):
    """Create communication poster."""

    current_tab = "posters"

    def get_success_url(self, **kwargs):
        return reverse_lazy("club:poster_list", kwargs={"club_id": self.club.id})

    def get_object(self, *args, **kwargs):
        return self.club


class PosterEditView(ClubTabsMixin, PosterEditBaseView):
    """Edit communication poster."""

    current_tab = "posters"
    extra_context = {"app": "club"}

    def get_success_url(self):
        return reverse_lazy("club:poster_list", kwargs={"club_id": self.club.id})


class PosterDeleteView(ClubTabsMixin, PosterDeleteBaseView):
    """Delete communication poster."""

    current_tab = "posters"

    def get_success_url(self):
        return reverse_lazy("club:poster_list", kwargs={"club_id": self.club.id})
