import json
from functools import cached_property

from django import forms
from django.conf import settings
from django.core.paginator import Paginator
from django.db import models
from django.db.models.functions import Greatest
from django.http import HttpResponseRedirect
from django.utils.translation import gettext_lazy
from modelcluster.contrib.taggit import ClusterTaggableManager
from modelcluster.fields import ParentalKey
from taggit.models import TaggedItemBase
from wagtail.admin.edit_handlers import (
    CommentPanel,
    FieldPanel,
    HelpPanel,
    MultiFieldPanel,
    ObjectList,
    PublishingPanel,
    StreamFieldPanel,
    TabbedInterface,
)
from wagtail.contrib.routable_page.models import RoutablePageMixin, route
from wagtail.core import blocks
from wagtail.core.fields import RichTextField, StreamField
from wagtail.core.models import Page
from wagtail.images.edit_handlers import ImageChooserPanel
from wagtailmetadata.models import MetadataPageMixin

from shared.models import ArticleMixin, SubpageMixin
from shared.utils import get_subpage_url
from tuning import help

from .constants import (
    ARTICLE_RICH_TEXT_FEATURES,
    ARTICLES_PER_PAGE,
    BENEFITS_CHOICES,
    CANDIDATE_RICH_TEXT_FEATURES,
    CHILDLESS,
    COUNTRYSIDE,
    CULTURE,
    EDUCATION,
    EXTRA_FEATURES,
    HEALTH,
    HOUSING,
    MATURE,
    MINISTRY_AGRICULTURE,
    MINISTRY_ARCHETYPES,
    MINISTRY_BUSINESS,
    MINISTRY_CHOICES,
    MINISTRY_COUNTRYSIDE,
    MINISTRY_CULTURE,
    MINISTRY_DEFENSE,
    MINISTRY_ENVIRONMENT,
    MINISTRY_FINANCES,
    MINISTRY_FOREIGN,
    MINISTRY_HEALTH,
    MINISTRY_INTERIOR,
    MINISTRY_JUSTICE,
    MINISTRY_OPTIONS,
    MINISTRY_SCHOOLS,
    MINISTRY_SOCIAL,
    MINISTRY_TRANSPORT,
    NATURE,
    OCCUPATION_BUSINESS,
    PARENTS,
    PARTY_CHOICES,
    PARTY_NAME,
    PIRATES,
    PLAN_ARCHETYPES,
    PLAN_CARE,
    PLAN_CHOICES,
    PLAN_CLIMATE,
    PLAN_CORRUPTION,
    PLAN_COUNTRYSIDE,
    PLAN_DIGITAL,
    PLAN_ECONOMICS,
    PLAN_MANAGEMENT,
    PLAN_OPTIONS,
    PLAN_SAFE_COUNTRY,
    PROGRAM_POINTS_PER_PAGE,
    REGION_CHOICES,
    REGION_NAME_VARIANT,
    REGION_OPTIONS,
    REGION_SLUGS,
    RESTRICTED_FEATURES,
    SENIORS,
    SPORT,
    STANDARD_FEATURES,
    STUDENTS,
    STYLE_CHOICES,
    STYLE_CSS,
    TECHNOLOGY,
    TOP_CANDIDATES_NUM,
    WEALTH_BAD,
    WHITE,
    WORKING_SENIORS,
)
from .forms import ProgramAppForm, ProgramPointPageForm
from .utils import get_archetype

NO_SEARCH_IMAGE_USE_PHOTO = (
    "Pokud není zadán <strong>Search image</strong>, použije se <strong>hlavní "
    "fotka</strong> (tab obsah)."
)


class LinkBlock(blocks.StructBlock):
    title = blocks.CharBlock(label="titulek")
    url = blocks.URLBlock(label="odkaz")

    class Meta:
        icon = "link-external"
        label = "odkaz"


class Elections2021HomePage(Page, MetadataPageMixin):
    ### FIELDS

    header_links = StreamField(
        [("link", LinkBlock())], verbose_name="odkazy v záhlaví", blank=True
    )
    footer_links = StreamField(
        [("link", LinkBlock())], verbose_name="odkazy v zápatí", blank=True
    )
    matomo_id = models.IntegerField(
        "Matomo ID pro sledování návštěvnosti", blank=True, null=True
    )

    ### PANELS

    promote_panels = [
        MultiFieldPanel(
            [
                FieldPanel("seo_title"),
                FieldPanel("search_description"),
                ImageChooserPanel("search_image"),
                HelpPanel(help.build(help.IMPORTANT_TITLE)),
            ],
            gettext_lazy("Common page configuration"),
        ),
    ]

    settings_panels = [
        FieldPanel("matomo_id"),
        StreamFieldPanel("header_links"),
        StreamFieldPanel("footer_links"),
        CommentPanel(),
    ]

    ### RELATIONS

    subpage_types = [
        "elections2021.Elections2021ArticlesPage",
        "elections2021.Elections2021CandidatesListPage",
        "elections2021.Elections2021CandidatesMapPage",
        "elections2021.Elections2021ProgramPage",
        "elections2021.Elections2021QuestionsPage",
        "elections2021.Elections2021ProgramAppPage",
    ]

    ### OTHERS

    class Meta:
        verbose_name = "Koaliční web 2021"

    @property
    def root_page(self):
        return self

    @cached_property
    def articles_page_url(self):
        return get_subpage_url(self, Elections2021ArticlesPage)

    @cached_property
    def candidates_list_page_url(self):
        try:
            return (
                self.get_descendants()
                .type(Elections2021CandidatesListPage)
                .live()
                .specific()
                .first()
                .get_region_list_url()
            )
        except (Page.DoesNotExist, AttributeError):
            return "#"

    @cached_property
    def candidates_map_page_url(self):
        return get_subpage_url(self, Elections2021CandidatesMapPage)

    @cached_property
    def questions_page_url(self):
        return get_subpage_url(self, Elections2021QuestionsPage)

    @cached_property
    def program_page_url(self):
        return get_subpage_url(self, Elections2021ProgramPage)

    @cached_property
    def program_app_page_url(self):
        return get_subpage_url(self, Elections2021ProgramAppPage)


class Elections2021ArticleTag(TaggedItemBase):
    content_object = ParentalKey(
        "elections2021.Elections2021ArticlePage", on_delete=models.CASCADE
    )


class Elections2021ArticlePage(ArticleMixin, SubpageMixin, MetadataPageMixin, Page):
    ### FIELDS

    text = RichTextField("článek", blank=True, features=ARTICLE_RICH_TEXT_FEATURES)
    tags = ClusterTaggableManager(through=Elections2021ArticleTag, blank=True)
    card_style = models.CharField(
        "styl karty článku", choices=STYLE_CHOICES, default=WHITE, max_length=10
    )

    ### PANELS

    content_panels = ArticleMixin.content_panels + [
        FieldPanel("tags"),
        FieldPanel("card_style"),
    ]

    promote_panels = [
        MultiFieldPanel(
            [
                FieldPanel("slug"),
                FieldPanel("seo_title"),
                FieldPanel("search_description"),
                HelpPanel(help.build(help.NO_SEO_TITLE, help.NO_DESCRIPTION_USE_PEREX)),
            ],
            gettext_lazy("Common page configuration"),
        ),
    ]

    settings_panels = [PublishingPanel(), CommentPanel()]

    ### RELATIONS

    parent_page_types = ["elections2021.Elections2021ArticlesPage"]
    subpage_types = []

    ### OTHERS

    class Meta:
        verbose_name = "Aktualita"

    def get_meta_image(self):
        return self.image

    def get_meta_description(self):
        if self.search_description:
            return self.search_description
        if len(self.perex) > 150:
            return str(self.perex)[:150] + "..."
        return self.perex

    def card_css_class(self):
        return STYLE_CSS[self.card_style]

    def get_context(self, request):
        context = super().get_context(request)
        context["related_articles"] = (
            self.get_siblings(inclusive=False)
            .live()
            .specific()
            .order_by("-elections2021articlepage__date")[:3]
        )
        return context


class Elections2021ArticlesPage(SubpageMixin, MetadataPageMixin, Page):
    ### FIELDS

    photo = models.ForeignKey(
        "wagtailimages.Image",
        on_delete=models.PROTECT,
        blank=True,
        null=True,
        verbose_name="hlavní fotka",
    )

    ### PANELS

    content_panels = Page.content_panels + [ImageChooserPanel("photo")]

    promote_panels = [
        MultiFieldPanel(
            [
                FieldPanel("slug"),
                FieldPanel("seo_title"),
                FieldPanel("search_description"),
                ImageChooserPanel("search_image"),
                HelpPanel(help.build(help.NO_SEO_TITLE, NO_SEARCH_IMAGE_USE_PHOTO)),
            ],
            gettext_lazy("Common page configuration"),
        ),
    ]

    settings_panels = [CommentPanel()]

    ### RELATIONS

    parent_page_types = ["elections2021.Elections2021HomePage"]
    subpage_types = ["elections2021.Elections2021ArticlePage"]

    ### OTHERS

    class Meta:
        verbose_name = "Aktuality"

    def get_meta_image(self):
        return self.search_image or self.photo

    def get_context(self, request):
        context = super().get_context(request)
        context["articles"] = Paginator(
            self.get_children()
            .live()
            .specific()
            .order_by("-elections2021articlepage__date"),
            ARTICLES_PER_PAGE,
        ).get_page(request.GET.get("page"))
        return context


class Elections2021CandidatesListPage(
    SubpageMixin, MetadataPageMixin, RoutablePageMixin, Page
):
    ### FIELDS

    photo = models.ForeignKey(
        "wagtailimages.Image",
        on_delete=models.PROTECT,
        blank=True,
        null=True,
        verbose_name="hlavní fotka",
    )

    ### PANELS

    content_panels = Page.content_panels + [ImageChooserPanel("photo")]

    promote_panels = [
        MultiFieldPanel(
            [
                FieldPanel("slug"),
                FieldPanel("seo_title"),
                FieldPanel("search_description"),
                ImageChooserPanel("search_image"),
                HelpPanel(help.build(help.NO_SEO_TITLE, NO_SEARCH_IMAGE_USE_PHOTO)),
            ],
            gettext_lazy("Common page configuration"),
        ),
    ]

    settings_panels = [CommentPanel()]

    ### RELATIONS

    parent_page_types = ["elections2021.Elections2021HomePage"]
    subpage_types = ["elections2021.Elections2021CandidatePage"]

    ### OTHERS

    class Meta:
        verbose_name = "Kandidáti"

    def get_meta_image(self):
        return self.search_image or self.photo

    def get_context(self, request):
        context = super().get_context(request)
        context["region_options"] = REGION_OPTIONS
        return context

    def get_region_list_url(self, slug=None):
        if slug is None:
            slug = list(REGION_SLUGS.keys())[0]
        return self.url + self.reverse_subpage("region_list", args=(slug,))

    @route(r"^$")
    @route(r"^kraj/$")
    @route(r"^kraj/([a-z]+)/$")
    def region_list(self, request, param=None):
        region = param if param in REGION_SLUGS else None
        if not region:
            return HttpResponseRedirect(self.get_region_list_url())

        candidates = (
            self.get_children()
            .filter(elections2021candidatepage__region=REGION_SLUGS[region])
            .live()
            .specific()
            .order_by("elections2021candidatepage__number")
        )

        context = {
            "active_region": region,
            "candidates_top": candidates[:TOP_CANDIDATES_NUM],
            "candidates_bottom": candidates[TOP_CANDIDATES_NUM:],
        }
        return self.render(request, context_overrides=context)


class Elections2021CandidatesMapPage(SubpageMixin, MetadataPageMixin, Page):
    ### FIELDS

    photo = models.ForeignKey(
        "wagtailimages.Image",
        on_delete=models.PROTECT,
        blank=True,
        null=True,
        verbose_name="hlavní fotka",
    )

    ### PANELS

    content_panels = Page.content_panels + [ImageChooserPanel("photo")]

    promote_panels = [
        MultiFieldPanel(
            [
                FieldPanel("slug"),
                FieldPanel("seo_title"),
                FieldPanel("search_description"),
                ImageChooserPanel("search_image"),
                HelpPanel(help.build(help.NO_SEO_TITLE, NO_SEARCH_IMAGE_USE_PHOTO)),
            ],
            gettext_lazy("Common page configuration"),
        ),
    ]

    settings_panels = [CommentPanel()]

    ### RELATIONS

    parent_page_types = ["elections2021.Elections2021HomePage"]
    subpage_types = []

    ### OTHERS

    class Meta:
        verbose_name = "Kandidáti mapa"

    def get_meta_image(self):
        return self.search_image or self.photo


class Elections2021CandidatePage(SubpageMixin, MetadataPageMixin, Page):
    ### FIELDS

    party = models.CharField(
        "strana", choices=PARTY_CHOICES, default=PIRATES, max_length=6
    )
    region = models.CharField("kraj", choices=REGION_CHOICES, max_length=3)
    number = models.IntegerField("pořadí")
    age = models.IntegerField("věk")
    occupation = models.CharField("povolání", max_length=255)
    city = models.CharField("bydliště", max_length=100)
    resume = RichTextField("medailonek", features=CANDIDATE_RICH_TEXT_FEATURES)
    email = models.EmailField("email", null=True, blank=True)
    phone = models.CharField("telefon", null=True, blank=True, max_length=20)
    facebook_url = models.URLField("Facebook URL", blank=True, null=True)
    twitter_url = models.URLField("Twitter URL", blank=True, null=True)
    instagram_url = models.URLField("Instagram URL", blank=True, null=True)
    website_url = models.URLField("webová stránka", blank=True, null=True)
    photo = models.ForeignKey(
        "wagtailimages.Image",
        on_delete=models.PROTECT,
        blank=True,
        null=True,
        verbose_name="foto",
    )

    ### PANELS

    content_panels = Page.content_panels + [
        MultiFieldPanel(
            [
                FieldPanel("party", widget=forms.RadioSelect),
                FieldPanel("region"),
                FieldPanel("number"),
            ],
            "zařazení",
        ),
        MultiFieldPanel(
            [
                FieldPanel("age"),
                FieldPanel("occupation"),
                FieldPanel("city"),
            ],
            "osobní údaje",
        ),
        ImageChooserPanel("photo"),
        FieldPanel("resume"),
        MultiFieldPanel(
            [
                FieldPanel("email"),
                FieldPanel("phone"),
                FieldPanel("facebook_url"),
                FieldPanel("twitter_url"),
                FieldPanel("instagram_url"),
                FieldPanel("website_url"),
            ],
            "kontakty",
        ),
    ]

    promote_panels = [
        MultiFieldPanel(
            [
                FieldPanel("slug"),
            ],
            gettext_lazy("Common page configuration"),
        ),
    ]

    settings_panels = [CommentPanel()]

    ### RELATIONS

    parent_page_types = ["elections2021.Elections2021CandidatesListPage"]
    subpage_types = []

    ### OTHERS

    class Meta:
        verbose_name = "Detail kandidáta"

    def get_meta_image(self):
        return self.photo

    def get_meta_description(self):
        name = REGION_NAME_VARIANT[self.region]
        return f"Kandidát č. {self.number} za koalici Piráti a Starostové v {name}."

    @property
    def party_name(self):
        return PARTY_NAME[self.party]

    @property
    def is_pirate(self):
        return self.party == PIRATES

    def get_region_list_url(self):
        slug = next(slug for slug, code in REGION_SLUGS.items() if code == self.region)
        candidates_list = Elections2021CandidatesListPage.objects.live().first()
        return candidates_list.get_region_list_url(slug)


class Elections2021ProgramPage(
    SubpageMixin, MetadataPageMixin, RoutablePageMixin, Page
):
    ### FIELDS

    photo = models.ForeignKey(
        "wagtailimages.Image",
        on_delete=models.PROTECT,
        blank=True,
        null=True,
        verbose_name="hlavní fotka",
    )
    plan_economics_text = RichTextField(
        "Moderní ekonomika", blank=True, null=True, features=RESTRICTED_FEATURES
    )
    plan_digital_text = RichTextField(
        "Digitální revoluce", blank=True, null=True, features=RESTRICTED_FEATURES
    )
    plan_corruption_text = RichTextField(
        "Razantní boj s korupcí", blank=True, null=True, features=RESTRICTED_FEATURES
    )
    plan_climate_text = RichTextField(
        "Důraz na klima", blank=True, null=True, features=RESTRICTED_FEATURES
    )
    plan_countryside_text = RichTextField(
        "Rovnocenné regiony", blank=True, null=True, features=RESTRICTED_FEATURES
    )
    plan_management_text = RichTextField(
        "Profesionální stát", blank=True, null=True, features=RESTRICTED_FEATURES
    )
    plan_safe_country_text = RichTextField(
        "Sebevědomá a bezpečná země",
        blank=True,
        null=True,
        features=RESTRICTED_FEATURES,
    )
    plan_care_text = RichTextField(
        "Jistota péče a pomoci", blank=True, null=True, features=RESTRICTED_FEATURES
    )

    ### PANELS

    content_panels = Page.content_panels + [ImageChooserPanel("photo")]

    promote_panels = [
        MultiFieldPanel(
            [
                FieldPanel("slug"),
                FieldPanel("seo_title"),
                FieldPanel("search_description"),
                ImageChooserPanel("search_image"),
                HelpPanel(help.build(help.NO_SEO_TITLE, NO_SEARCH_IMAGE_USE_PHOTO)),
            ],
            gettext_lazy("Common page configuration"),
        ),
        CommentPanel(),
    ]

    plan_panels = [
        FieldPanel("plan_economics_text"),
        FieldPanel("plan_digital_text"),
        FieldPanel("plan_corruption_text"),
        FieldPanel("plan_climate_text"),
        FieldPanel("plan_countryside_text"),
        FieldPanel("plan_management_text"),
        FieldPanel("plan_safe_country_text"),
        FieldPanel("plan_care_text"),
    ]

    edit_handler = TabbedInterface(
        [
            ObjectList(content_panels, heading=gettext_lazy("Content")),
            ObjectList(promote_panels, heading=gettext_lazy("Promote")),
            ObjectList(plan_panels, heading="plány"),
        ]
    )

    ### RELATIONS

    parent_page_types = ["elections2021.Elections2021HomePage"]
    subpage_types = ["elections2021.Elections2021ProgramPointPage"]

    ### OTHERS

    class Meta:
        verbose_name = "Program"

    def get_meta_image(self):
        return self.search_image or self.photo

    def get_context(self, request, parent_context=None):
        context = super().get_context(request, parent_context=parent_context)
        context["plan_choices"] = PLAN_CHOICES
        context["ministry_choices"] = MINISTRY_CHOICES
        context["show_archetype_icon"] = True
        context["show_app_banner"] = True
        context["show_pagination"] = True
        context["active_my_program"] = False
        context["has_my_program"] = self.get_my_selection(request) is not None
        return context

    @staticmethod
    def get_archetype_image(archetype):
        return f"elections2021/images/archetype/{archetype}.svg"

    def get_my_program_url(self):
        return self.url + self.reverse_subpage("my_program")

    def get_my_selection(self, request):
        data = request.get_signed_cookie(settings.ELECTIONS2021_COOKIE_NAME, None)
        if data:
            try:
                return json.loads(data)
            except json.JSONDecodeError:
                pass
        return None

    @route(r"^$")
    def plan_all(self, request, param=None):
        points = Elections2021ProgramPointPage.objects.live().specific()
        points = Paginator(points, PROGRAM_POINTS_PER_PAGE).get_page(
            request.GET.get("page")
        )
        context = {"points": points}
        return self.render(request, context_overrides=context)

    @route(r"^plan/([a-z-]+)/$")
    def plan_detail(self, request, param=None):
        plan = param if param in PLAN_OPTIONS else None
        title = None
        head_text = ""
        head_image = ""

        if plan:
            title = next(title for key, title in PLAN_CHOICES if key == plan)
            head_image = self.get_archetype_image(PLAN_ARCHETYPES[plan])

        if plan == PLAN_ECONOMICS:
            head_text = self.plan_economics_text
            weights = ["weight_plan_economics"]
        elif plan == PLAN_DIGITAL:
            head_text = self.plan_digital_text
            weights = ["weight_plan_digital"]
        elif plan == PLAN_CORRUPTION:
            head_text = self.plan_corruption_text
            weights = ["weight_plan_corruption"]
        elif plan == PLAN_CLIMATE:
            head_text = self.plan_climate_text
            weights = ["weight_plan_climate"]
        elif plan == PLAN_COUNTRYSIDE:
            head_text = self.plan_countryside_text
            weights = ["weight_plan_countryside"]
        elif plan == PLAN_MANAGEMENT:
            head_text = self.plan_management_text
            weights = ["weight_plan_management"]
        elif plan == PLAN_SAFE_COUNTRY:
            head_text = self.plan_safe_country_text
            weights = ["weight_plan_safe_country"]
        elif plan == PLAN_CARE:
            head_text = self.plan_care_text
            weights = ["weight_plan_care"]

        context = {
            "active_plan": plan,
            "title": title,
            "head_image": head_image,
            "head_text": head_text,
            "points": Elections2021ProgramPointPage.filter_by_weights(weights),
            "show_app_banner": False,
            "show_pagination": False,
        }
        return self.render(request, context_overrides=context)

    @route(r"^resort/([a-z-]+)/$")
    def ministry_detail(self, request, param=None):
        ministry = param if param in MINISTRY_OPTIONS else None
        title = None
        head_text = ""
        head_image = ""

        if ministry:
            title = next(title for key, title in MINISTRY_CHOICES if key == ministry)
            head_image = self.get_archetype_image(MINISTRY_ARCHETYPES[ministry])

        if ministry == MINISTRY_TRANSPORT:
            weights = ["weight_ministry_transport"]
        elif ministry == MINISTRY_FINANCES:
            weights = ["weight_ministry_finances"]
        elif ministry == MINISTRY_CULTURE:
            weights = ["weight_ministry_culture"]
        elif ministry == MINISTRY_DEFENSE:
            weights = ["weight_ministry_defense"]
        elif ministry == MINISTRY_SOCIAL:
            weights = ["weight_ministry_social"]
        elif ministry == MINISTRY_COUNTRYSIDE:
            weights = ["weight_ministry_countryside"]
        elif ministry == MINISTRY_BUSINESS:
            weights = ["weight_ministry_business"]
        elif ministry == MINISTRY_JUSTICE:
            weights = ["weight_ministry_justice"]
        elif ministry == MINISTRY_SCHOOLS:
            weights = ["weight_ministry_schools"]
        elif ministry == MINISTRY_INTERIOR:
            weights = ["weight_ministry_interior"]
        elif ministry == MINISTRY_FOREIGN:
            weights = ["weight_ministry_foreign"]
        elif ministry == MINISTRY_HEALTH:
            weights = ["weight_ministry_health"]
        elif ministry == MINISTRY_AGRICULTURE:
            weights = ["weight_ministry_agriculture"]
        elif ministry == MINISTRY_ENVIRONMENT:
            weights = ["weight_ministry_environment"]

        context = {
            "active_ministry": ministry,
            "title": title,
            "head_image": head_image,
            "head_text": head_text,
            "points": Elections2021ProgramPointPage.filter_by_weights(weights),
            "show_archetype_icon": False,
            "show_app_banner": False,
            "show_pagination": False,
        }
        return self.render(request, context_overrides=context)

    @route(r"^muj-program/$")
    def my_program(self, request):
        selection = self.get_my_selection(request)
        if selection is None:
            response = HttpResponseRedirect(self.url)
            # očekávali jsme data z cookie, ale nepodařilo se je získat, tak pro
            # jistotu cookie smažeme kdyby náhodou existovala s poškozenými daty
            response.delete_cookie(settings.ELECTIONS2021_COOKIE_NAME)
            return response

        weights = []

        archetype = get_archetype(selection)
        if archetype == CHILDLESS:
            weights.append("weight_childless")
        elif archetype == PARENTS:
            weights.append("weight_parents")
        elif archetype == MATURE:
            weights.append("weight_mature")
        elif archetype == STUDENTS:
            weights.append("weight_students")
        elif archetype == SENIORS:
            weights.append("weight_seniors")
        elif archetype == WORKING_SENIORS:
            weights.append("weight_working_seniors")

        if selection["occupation"] == OCCUPATION_BUSINESS:
            weights.append("weight_self_employed")

        if selection["wealth"] == WEALTH_BAD:
            weights.append("weight_socially_weak")

        if NATURE in selection["topics"]:
            weights.append("weight_nature")
        if SPORT in selection["topics"]:
            weights.append("weight_sport")
        if HEALTH in selection["topics"]:
            weights.append("weight_health")
        if CULTURE in selection["topics"]:
            weights.append("weight_culture")
        if TECHNOLOGY in selection["topics"]:
            weights.append("weight_technology")
        if COUNTRYSIDE in selection["topics"]:
            weights.append("weight_countryside")
        if HOUSING in selection["topics"]:
            weights.append("weight_housing")
        if EDUCATION in selection["topics"]:
            weights.append("weight_education")

        points = Elections2021ProgramPointPage.filter_by_weights(weights)
        points = Paginator(points, PROGRAM_POINTS_PER_PAGE).get_page(
            request.GET.get("page")
        )
        context = {
            "title": "Program pro mě",
            "points": points,
            "show_app_banner": False,
            "active_my_program": True,
        }
        return self.render(request, context_overrides=context)


class QuestionBlock(blocks.StructBlock):
    question = blocks.CharBlock(label="otázka")
    answer = blocks.RichTextBlock(label="odpověď", features=STANDARD_FEATURES)

    class Meta:
        label = "otázka a odpověď"
        icon = "doc-full"
        template = "elections2021/_question_block.html"


class MainBenefitBlock(blocks.StructBlock):
    variant = blocks.ChoiceBlock(BENEFITS_CHOICES, label="název")
    text = blocks.RichTextBlock(label="text", features=STANDARD_FEATURES)

    class Meta:
        label = "hlavní benefit"
        icon = "pick"
        template = "elections2021/_main_benefit_block.html"

    def get_context(self, value, parent_context=None):
        context = super().get_context(value, parent_context=parent_context)
        context["photo"] = f"elections2021/images/benefits/{value['variant']}.jpg"
        context["title"] = next(
            title for num, title in BENEFITS_CHOICES if num == value["variant"]
        )
        return context


class BenefitBlock(blocks.StructBlock):
    title = blocks.CharBlock(label="název")
    text = blocks.RichTextBlock(label="text", features=STANDARD_FEATURES)

    class Meta:
        label = "benefit"
        icon = "pick"
        template = "elections2021/_benefit_block.html"


class Elections2021ProgramPointPage(SubpageMixin, MetadataPageMixin, Page):
    ### FIELDS

    annotation = RichTextField(
        "anotace", blank=True, null=True, features=RESTRICTED_FEATURES
    )
    problem = RichTextField(
        "problém", blank=True, null=True, features=RESTRICTED_FEATURES
    )
    context = RichTextField(
        "kontext problému", blank=True, null=True, features=RESTRICTED_FEATURES
    )
    ideal = RichTextField("ideál", blank=True, null=True, features=RESTRICTED_FEATURES)
    proposal = RichTextField(
        "navrhovaná opatření", blank=True, null=True, features=EXTRA_FEATURES
    )
    time_horizon_text = RichTextField(
        "časový horizont textově", blank=True, null=True, features=STANDARD_FEATURES
    )
    time_horizon_number = models.IntegerField(
        "časový horizont číslo", blank=True, null=True
    )
    time_horizon_unit = models.CharField(
        "časový horizont jednotka", max_length=20, blank=True, null=True
    )
    already_done = RichTextField(
        "co jsme už udělali", blank=True, null=True, features=EXTRA_FEATURES
    )
    sources = RichTextField("zdroje", blank=True, null=True, features=STANDARD_FEATURES)

    faq = StreamField(
        [("question", QuestionBlock())],
        verbose_name="FAQ",
        blank=True,
    )
    related_points = StreamField(
        [
            (
                "point",
                blocks.PageChooserBlock(
                    label="programový bod",
                    page_type=["elections2021.Elections2021ProgramPointPage"],
                ),
            )
        ],
        verbose_name="související body",
        blank=True,
    )
    benefit_for_all = RichTextField(
        "benefit pro společnost", blank=True, null=True, features=RESTRICTED_FEATURES
    )
    benefits_main = StreamField(
        [("benefit", MainBenefitBlock())],
        verbose_name="hlavní benefity",
        blank=True,
    )
    benefits = StreamField(
        [("benefit", BenefitBlock())],
        verbose_name="ostatní benefity",
        blank=True,
    )

    # target weights
    weight_childless = models.IntegerField("váha bezdětní", default=0)
    weight_parents = models.IntegerField("váha rodiče", default=0)
    weight_mature = models.IntegerField("váha zralí", default=0)
    weight_seniors = models.IntegerField("váha senioři", default=0)
    weight_working_seniors = models.IntegerField("váha pracující senioři", default=0)
    weight_students = models.IntegerField("váha studenti", default=0)
    weight_self_employed = models.IntegerField("váha OSVČ", default=0)
    weight_socially_weak = models.IntegerField("váha sociálně slabí", default=0)
    weight_nature = models.IntegerField("váha příroda", default=0)
    weight_sport = models.IntegerField("váha sport", default=0)
    weight_health = models.IntegerField("váha zdraví", default=0)
    weight_culture = models.IntegerField("váha kultura", default=0)
    weight_technology = models.IntegerField("váha technologie", default=0)
    weight_countryside = models.IntegerField("váha regiony", default=0)
    weight_housing = models.IntegerField("váha bydlení", default=0)
    weight_education = models.IntegerField("váha vzdělávání", default=0)
    weight_plan_economics = models.IntegerField("váha moderní ekonomika", default=0)
    weight_plan_digital = models.IntegerField("váha digitalizace státu", default=0)
    weight_plan_corruption = models.IntegerField(
        "váha protikorupční strategie", default=0
    )
    weight_plan_climate = models.IntegerField("váha plán klima", default=0)
    weight_plan_countryside = models.IntegerField("váha plán rozvoj regionů", default=0)
    weight_plan_management = models.IntegerField("váha plán řízení státu", default=0)
    weight_plan_safe_country = models.IntegerField(
        "váha plán sebevědomá země", default=0
    )
    weight_plan_care = models.IntegerField("váha plán jistota péče", default=0)
    weight_ministry_transport = models.IntegerField(
        "váha ministerstvo dopravy", default=0
    )
    weight_ministry_finances = models.IntegerField(
        "váha ministerstvo financí", default=0
    )
    weight_ministry_culture = models.IntegerField(
        "váha ministerstvo kultury", default=0
    )
    weight_ministry_defense = models.IntegerField("váha ministerstvo obrany", default=0)
    weight_ministry_social = models.IntegerField(
        "váha ministerstvo práce a sociálních věcí", default=0
    )
    weight_ministry_countryside = models.IntegerField(
        "váha ministerstvo pro místní rozvoj", default=0
    )
    weight_ministry_business = models.IntegerField(
        "váha ministerstvo průmyslu a obchodu", default=0
    )
    weight_ministry_justice = models.IntegerField(
        "váha ministerstvo spravedlnosti", default=0
    )
    weight_ministry_schools = models.IntegerField(
        "váha ministerstvo školství, mládeže a tělovýchovy", default=0
    )
    weight_ministry_interior = models.IntegerField(
        "váha ministerstvo vnitra", default=0
    )
    weight_ministry_foreign = models.IntegerField(
        "váha ministerstvo zahraničních věcí", default=0
    )
    weight_ministry_health = models.IntegerField(
        "váha ministerstvo zdravotnictví", default=0
    )
    weight_ministry_agriculture = models.IntegerField(
        "váha ministerstvo zemědělství", default=0
    )
    weight_ministry_environment = models.IntegerField(
        "váha ministerstvo životního prostředí", default=0
    )

    ### PANELS

    content_panels = Page.content_panels + [
        FieldPanel("annotation"),
        FieldPanel("problem"),
        FieldPanel("context"),
        FieldPanel("ideal"),
        FieldPanel("proposal"),
        MultiFieldPanel(
            [
                FieldPanel("time_horizon_number"),
                FieldPanel("time_horizon_unit"),
                FieldPanel("time_horizon_text"),
            ],
            "časový horizont",
        ),
        FieldPanel("already_done"),
        FieldPanel("sources"),
    ]

    promote_panels = [
        MultiFieldPanel(
            [
                FieldPanel("slug"),
                FieldPanel("seo_title"),
                FieldPanel("search_description"),
                ImageChooserPanel("search_image"),
                HelpPanel(help.build(help.NO_SEO_TITLE)),
            ],
            gettext_lazy("Common page configuration"),
        ),
        CommentPanel(),
    ]

    faq_panels = [StreamFieldPanel("faq")]

    related_panels = [StreamFieldPanel("related_points")]

    benefits_panels = [
        FieldPanel("benefit_for_all"),
        StreamFieldPanel("benefits_main"),
        StreamFieldPanel("benefits"),
    ]

    weights_panels = [
        MultiFieldPanel(
            [
                FieldPanel("weight_childless"),
                FieldPanel("weight_parents"),
                FieldPanel("weight_mature"),
                FieldPanel("weight_seniors"),
                FieldPanel("weight_working_seniors"),
                FieldPanel("weight_students"),
            ],
            "archetypy",
        ),
        MultiFieldPanel(
            [
                FieldPanel("weight_self_employed"),
                FieldPanel("weight_socially_weak"),
            ],
            "doplňující",
        ),
        MultiFieldPanel(
            [
                FieldPanel("weight_nature"),
                FieldPanel("weight_sport"),
                FieldPanel("weight_health"),
                FieldPanel("weight_culture"),
                FieldPanel("weight_technology"),
                FieldPanel("weight_countryside"),
                FieldPanel("weight_housing"),
                FieldPanel("weight_education"),
            ],
            "zájmy",
        ),
        MultiFieldPanel(
            [
                FieldPanel("weight_plan_economics"),
                FieldPanel("weight_plan_digital"),
                FieldPanel("weight_plan_corruption"),
                FieldPanel("weight_plan_climate"),
                FieldPanel("weight_plan_countryside"),
                FieldPanel("weight_plan_management"),
                FieldPanel("weight_plan_safe_country"),
                FieldPanel("weight_plan_care"),
            ],
            "plány",
        ),
        MultiFieldPanel(
            [
                FieldPanel("weight_ministry_transport"),
                FieldPanel("weight_ministry_finances"),
                FieldPanel("weight_ministry_culture"),
                FieldPanel("weight_ministry_defense"),
                FieldPanel("weight_ministry_social"),
                FieldPanel("weight_ministry_countryside"),
                FieldPanel("weight_ministry_business"),
                FieldPanel("weight_ministry_justice"),
                FieldPanel("weight_ministry_schools"),
                FieldPanel("weight_ministry_interior"),
                FieldPanel("weight_ministry_foreign"),
                FieldPanel("weight_ministry_health"),
                FieldPanel("weight_ministry_agriculture"),
                FieldPanel("weight_ministry_environment"),
            ],
            "ministerstva",
        ),
    ]

    import_panels = [
        MultiFieldPanel(
            [
                FieldPanel("import_file"),
                HelpPanel(
                    'Soubor z Goodle Docs stáhněte jako "Webová stránka (komprimovaný '
                    ' HTML soubor)" a ten nahrajte do formuláře.'
                ),
            ],
            "import programového bodu",
        ),
    ]

    edit_handler = TabbedInterface(
        [
            ObjectList(content_panels, heading=gettext_lazy("Content")),
            ObjectList(promote_panels, heading=gettext_lazy("Promote")),
            ObjectList(faq_panels, heading="FAQ"),
            ObjectList(benefits_panels, heading="benefity"),
            ObjectList(related_panels, heading="související"),
            ObjectList(weights_panels, heading="váhy"),
            ObjectList(import_panels, heading="import"),
        ]
    )

    ### RELATIONS

    parent_page_types = ["elections2021.Elections2021ProgramPage"]
    subpage_types = []

    ### OTHERS

    base_form_class = ProgramPointPageForm

    class Meta:
        verbose_name = "Programový bod"

    @property
    def archetype(self):
        if self.weight_ministry_transport:
            return MINISTRY_ARCHETYPES[MINISTRY_TRANSPORT]
        if self.weight_ministry_finances:
            return MINISTRY_ARCHETYPES[MINISTRY_FINANCES]
        if self.weight_ministry_culture:
            return MINISTRY_ARCHETYPES[MINISTRY_CULTURE]
        if self.weight_ministry_defense:
            return MINISTRY_ARCHETYPES[MINISTRY_DEFENSE]
        if self.weight_ministry_social:
            return MINISTRY_ARCHETYPES[MINISTRY_SOCIAL]
        if self.weight_ministry_countryside:
            return MINISTRY_ARCHETYPES[MINISTRY_COUNTRYSIDE]
        if self.weight_ministry_business:
            return MINISTRY_ARCHETYPES[MINISTRY_BUSINESS]
        if self.weight_ministry_justice:
            return MINISTRY_ARCHETYPES[MINISTRY_JUSTICE]
        if self.weight_ministry_schools:
            return MINISTRY_ARCHETYPES[MINISTRY_SCHOOLS]
        if self.weight_ministry_interior:
            return MINISTRY_ARCHETYPES[MINISTRY_INTERIOR]
        if self.weight_ministry_foreign:
            return MINISTRY_ARCHETYPES[MINISTRY_FOREIGN]
        if self.weight_ministry_health:
            return MINISTRY_ARCHETYPES[MINISTRY_HEALTH]
        if self.weight_ministry_agriculture:
            return MINISTRY_ARCHETYPES[MINISTRY_AGRICULTURE]
        if self.weight_ministry_environment:
            return MINISTRY_ARCHETYPES[MINISTRY_ENVIRONMENT]
        return ""

    @classmethod
    def filter_by_weights(cls, weights):
        points = cls.objects.live().specific()
        if len(weights) > 1:
            return (
                points.annotate(max_weight=Greatest(*weights))
                .filter(max_weight__gt=0)
                .order_by("-max_weight")
            )
        else:
            condition = {f"{weights[0]}__gt": 0}
            order = f"-{weights[0]}"
            return points.filter(**condition).order_by(order)


class RichQuestionBlock(blocks.StructBlock):
    question = blocks.CharBlock(label="otázka")
    answer = blocks.RichTextBlock(label="odpověď", features=ARTICLE_RICH_TEXT_FEATURES)

    class Meta:
        label = "otázka a odpověď"
        icon = "doc-full"
        template = "elections2021/_rich_question_block.html"


class Elections2021QuestionsPage(SubpageMixin, MetadataPageMixin, Page):
    ### FIELDS

    intro = RichTextField(
        "úvodní text", blank=True, features=ARTICLE_RICH_TEXT_FEATURES
    )
    photo = models.ForeignKey(
        "wagtailimages.Image",
        on_delete=models.PROTECT,
        blank=True,
        null=True,
        verbose_name="hlavní fotka",
    )
    myths = StreamField(
        [("question", RichQuestionBlock())],
        verbose_name="mýty o koalici",
        blank=True,
    )
    elections = StreamField(
        [("question", RichQuestionBlock())],
        verbose_name="otázky k volbám",
        blank=True,
    )

    ### PANELS

    content_panels = Page.content_panels + [
        FieldPanel("intro"),
        ImageChooserPanel("photo"),
    ]

    promote_panels = [
        MultiFieldPanel(
            [
                FieldPanel("slug"),
                FieldPanel("seo_title"),
                FieldPanel("search_description"),
                ImageChooserPanel("search_image"),
                HelpPanel(help.build(help.NO_SEO_TITLE, NO_SEARCH_IMAGE_USE_PHOTO)),
            ],
            gettext_lazy("Common page configuration"),
        ),
        CommentPanel(),
    ]

    myths_panels = [StreamFieldPanel("myths")]

    elections_panels = [StreamFieldPanel("elections")]

    edit_handler = TabbedInterface(
        [
            ObjectList(content_panels, heading=gettext_lazy("Content")),
            ObjectList(myths_panels, heading="mýty"),
            ObjectList(elections_panels, heading="volby"),
            ObjectList(promote_panels, heading=gettext_lazy("Promote")),
        ]
    )

    ### RELATIONS

    parent_page_types = ["elections2021.Elections2021HomePage"]
    subpage_types = []

    ### OTHERS

    class Meta:
        verbose_name = "FAQ"

    def get_meta_image(self):
        return self.search_image or self.photo


class Elections2021ProgramAppPage(SubpageMixin, MetadataPageMixin, Page):
    ### FIELDS

    info_text = RichTextField(
        "základní informace", blank=True, null=True, features=RESTRICTED_FEATURES
    )

    ### PANELS

    content_panels = Page.content_panels + [FieldPanel("info_text")]

    promote_panels = [
        MultiFieldPanel(
            [
                FieldPanel("slug"),
                FieldPanel("seo_title"),
                FieldPanel("search_description"),
                ImageChooserPanel("search_image"),
                HelpPanel(help.build(help.NO_SEO_TITLE)),
            ],
            gettext_lazy("Common page configuration"),
        ),
    ]

    settings_panels = [CommentPanel()]

    ### RELATIONS

    parent_page_types = ["elections2021.Elections2021HomePage"]
    subpage_types = []

    ### OTHERS

    class Meta:
        verbose_name = "Programová aplikace"

    def serve(self, request):
        if request.method == "POST":
            form = ProgramAppForm(request.POST)
            if form.is_valid():
                program_page = Elections2021ProgramPage.objects.live().first()
                response = HttpResponseRedirect(program_page.get_my_program_url())
                response.set_signed_cookie(
                    settings.ELECTIONS2021_COOKIE_NAME,
                    json.dumps(form.cleaned_data),
                    secure=settings.SESSION_COOKIE_SECURE,
                    httponly=settings.SESSION_COOKIE_HTTPONLY,
                )
                return response
        return super().serve(request)