from datetime import date, datetime

from django.contrib import messages
from django.core.exceptions import PermissionDenied
from django.core.mail import EmailMessage
from django.db import models
from django.shortcuts import render
from django_ratelimit.core import is_ratelimited
from modelcluster.contrib.taggit import ClusterTaggableManager
from modelcluster.fields import ParentalKey, ParentalManyToManyField
from taggit.models import TaggedItemBase
from wagtail.admin.panels import (
    FieldPanel,
    HelpPanel,
    MultiFieldPanel,
    ObjectList,
    TabbedInterface,
)
from wagtail.blocks import RichTextBlock
from wagtail.contrib.routable_page.models import route
from wagtail.fields import RichTextField, StreamField
from wagtail.models import Page
from wagtailmetadata.models import MetadataPageMixin

from shared import blocks as shared_blocks
from shared.const import RICH_TEXT_DEFAULT_FEATURES
from shared.models import (  # MenuMixin,
    ArticleMixin,
    ExtendedMetadataHomePageMixin,
    ExtendedMetadataPageMixin,
    MainArticlePageMixin,
    MainArticlesPageMixin,
    MainContactPageMixin,
    MainHomePageMixin,
    MainPeoplePageMixin,
    MainPersonPageMixin,
    MainProgramPageMixin,
    MainSearchPageMixin,
    MainSimplePageMixin,
    PageInMenuMixin,
    SharedTaggedMainArticle,
    SubpageMixin,
)
from shared.utils import make_promote_panels

from . import blocks
from .forms import CareerSubmissionForm, MainArticlesPageForm


class MainHomePage(MainHomePageMixin):
    # menu

    popout_button_name = models.CharField(
        "Název vyskakovacího tlačítka",
        max_length=16,
        blank=True,
        null=True,
    )

    popout_button_content = StreamField(
        [
            ("navbar_menu_item", shared_blocks.NavbarMenuItemBlock()),
        ],
        verbose_name="Obsah vyskakovacího tlačítka",
        blank=True,
        use_json_field=True,
    )

    ecomail_newsletter_list_id = models.IntegerField(
        "ID Ecomail newsletteru",
        blank=True,
        null=True,
    )

    ecomail_newsletter_list_tags = models.CharField(
        "Tagy k přidání novým odběratelům na Ecomailu",
        max_length=128,
        blank=True,
        null=True,
        help_text="Oddělte čárkou, například 'Tag1,Tag2,Tag3'. Bez mezer.",
    )

    # content
    content = StreamField(
        [
            ("carousel", blocks.HomePageCarouseSlideBlock()),
            (
                "news",
                shared_blocks.NewsBlock(
                    template="styleguide2/includes/organisms/articles/articles_section.html"
                ),
            ),
            # ("europarl_news", blocks.EuroparlNewsBlock()),
            ("people", shared_blocks.PeopleOverviewBlock()),
            ("regions", blocks.RegionsBlock()),
            ("boxes", blocks.BoxesBlock()),
        ],
        verbose_name="Hlavní obsah",
        blank=True,
        use_json_field=True,
    )

    # footer
    footer_person_list = StreamField(
        [("person", blocks.PersonContactBlock())],
        verbose_name="Osoby v zápatí webu",
        blank=True,
        max_num=6,
        use_json_field=True,
    )

    # settings
    gdpr_and_cookies_page = models.ForeignKey(
        "main.MainSimplePage",
        verbose_name="Stránka pro GDPR",
        on_delete=models.PROTECT,
        blank=True,
        null=True,
    )

    subpage_types = [
        "main.MainArticlesPage",
        "main.MainProgramPage",
        "main.MainPeoplePage",
        "main.MainPersonPage",
        "main.MainSimplePage",
        "main.MainContactPage",
        "main.MainCrossroadPage",
        "main.MainHoaxPage",
        "main.MainSearchPage",
        "main.MainResultsPage",
        "main.MainCareersPage",
    ]

    ### PANELS

    menu_panels = MainHomePageMixin.menu_panels + [
        FieldPanel("popout_button_name"),
        FieldPanel("popout_button_content"),
    ]

    edit_handler = TabbedInterface(
        [
            ObjectList(MainHomePageMixin.content_panels, heading="Obsah"),
            ObjectList(menu_panels, heading="Hlavička"),
            ObjectList(MainHomePageMixin.footer_panels, heading="Patička"),
            ObjectList(
                MainHomePageMixin.settings_panels
                + [
                    FieldPanel("ecomail_newsletter_list_id"),
                    FieldPanel("ecomail_newsletter_list_tags"),
                ],
                heading="Nastavení",
            ),
            ObjectList(MainHomePageMixin.promote_panels, heading="Metadata"),
        ]
    )

    ### OTHERS

    class Meta:
        verbose_name = "HomePage pirati.cz"

    @property
    def careers_page(self):
        return self._first_subpage_of_type(MainCareersPage)

    @property
    def article_page_model(self):
        return MainArticlePage

    @property
    def articles_page_model(self):
        return MainArticlesPage

    @property
    def contact_page_model(self):
        return MainContactPage

    @property
    def search_page_model(self):
        return MainSearchPage

    @property
    def people_page_model(self):
        return MainPeoplePage

    @property
    def root_page(self):
        return self

    def _first_subpage_of_type(self, page_type) -> Page or None:
        try:
            return self.get_descendants().type(page_type).live().specific()[0]
        except IndexError:
            return None

    @route(r"^sdilene/$", name="shared")
    def shared(self, request):
        return self.setup_article_page_context(request)


class MainArticleTag(TaggedItemBase):
    content_object = ParentalKey(
        "main.MainArticlePage",
        on_delete=models.CASCADE,
        related_name="main_tagged_items",
    )


class MainArticlesPage(MainArticlesPageMixin):
    base_form_class = MainArticlesPageForm

    displayed_tags = ParentalManyToManyField(
        "main.MainArticleTag",
        verbose_name="Z tohoto webu",
        related_name="+",
        blank=True,
    )

    displayed_shared_tags = ParentalManyToManyField(
        "shared.SharedTag",
        verbose_name="Sdílecí",
        related_name="+",
        blank=True,
    )

    parent_page_types = ["main.MainHomePage"]
    subpage_types = ["main.MainArticlePage"]


class MainArticlePage(MainArticlePageMixin):
    author_page = models.ForeignKey(
        "main.MainPersonPage",
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        verbose_name="Stránka autora (osoby)",
    )
    tags = ClusterTaggableManager(
        through=MainArticleTag, related_name="main_tagged_articles", blank=True
    )
    shared_tags = ClusterTaggableManager(
        verbose_name="Štítky pro sdílení mezi weby",
        through=SharedTaggedMainArticle,
        blank=True,
    )

    parent_page_types = ["main.MainArticlesPage"]
    subpage_types = []


class MainProgramPage(MainProgramPageMixin):
    ### FIELDS

    program = StreamField(
        [
            ("program_group", shared_blocks.ProgramGroupBlock()),
            ("program_group_crossroad", blocks.ProgramGroupBlockCrossroad()),
            ("program_group_popout", blocks.ProgramGroupBlockPopout()),
            ("program_group_with_candidates", blocks.ProgramGroupWithCandidatesBlock()),
            ("elections_program", blocks.ElectionsProgramBlock()),
        ],
        verbose_name="Programy",
        blank=True,
        use_json_field=True,
    )

    ### RELATIONS

    parent_page_types = ["main.MainHomePage"]
    subpage_types = []


class MainPeoplePage(MainPeoplePageMixin):
    content = StreamField(
        [
            ("people_group", blocks.PeopleGroupBlock(label="Seznam osob")),
            ("team_group", blocks.TeamBlock()),
        ],
        verbose_name="Lidé a týmy",
        blank=True,
        use_json_field=True,
    )

    parent_page_types = ["main.MainHomePage"]
    subpage_types = [
        "main.MainPersonPage",
        "main.MainSimplePage",
    ]


class MainPersonPage(MainPersonPageMixin):
    ### RELATIONS

    parent_page_types = ["main.MainPeoplePage"]


class MainSimplePage(MainSimplePageMixin):
    parent_page_types = [
        "main.MainHomePage",
        "main.MainSimplePage",
        "main.MainCrossroadPage",
        "main.MainPeoplePage",
    ]
    subpage_types = ["main.MainSimplePage"]


class MainContactPage(MainContactPageMixin):
    ### FIELDS

    contact_people = StreamField(
        [("item", blocks.PersonContactBlock())],
        verbose_name="Kontaktní osoby",
        blank=True,
        use_json_field=True,
    )

    ### RELATIONS

    parent_page_types = ["main.MainHomePage"]
    subpage_types = []


class MainCrossroadPage(
    ExtendedMetadataPageMixin, SubpageMixin, MetadataPageMixin, PageInMenuMixin, Page
):
    ### FIELDS

    headlined_cards_content = StreamField(
        [(("headlined_cards"), blocks.CardLinkWithHeadlineBlock())],
        verbose_name="Karty rozcestníku s nadpisem",
        blank=True,
        use_json_field=True,
    )
    cards_content = StreamField(
        [("cards", blocks.CardLinkBlock())],
        verbose_name="Karty rozcestníku",
        blank=True,
        use_json_field=True,
    )

    ### PANELS

    content_panels = Page.content_panels + [
        FieldPanel("headlined_cards_content"),
        FieldPanel("cards_content"),
    ]

    promote_panels = make_promote_panels()

    settings_panels = []

    ### RELATIONS

    parent_page_types = [
        "main.MainHomePage",
        "main.MainCrossroadPage",
    ]
    subpage_types = [
        "main.MainSimplePage",
        "main.MainCrossroadPage",
    ]
    ### OTHERS

    class Meta:
        verbose_name = "Rozcestník s kartami"


class MainHoaxPage(
    ExtendedMetadataPageMixin, SubpageMixin, MetadataPageMixin, PageInMenuMixin, Page
):
    ### FIELDS

    description = RichTextField(
        "Popis",
        blank=True,
        null=True,
    )

    content = StreamField(
        [(("hoax"), blocks.HoaxBlock())],
        verbose_name="Hoaxy a jejich vysvětlení",
        blank=True,
        use_json_field=True,
    )

    ### PANELS

    content_panels = Page.content_panels + [
        FieldPanel("description"),
        FieldPanel("content"),
    ]

    promote_panels = make_promote_panels()

    settings_panels = []

    ### RELATIONS

    parent_page_types = ["main.MainHomePage"]
    subpage_types = []

    ### OTHERS

    class Meta:
        verbose_name = "Hoaxy"


class MainResultsPage(
    ExtendedMetadataPageMixin, SubpageMixin, MetadataPageMixin, PageInMenuMixin, Page
):
    ### FIELDS

    content = StreamField(
        [
            (("flip_cards"), shared_blocks.FlipCardsBlock()),
            (
                "text",
                RichTextBlock(
                    template="styleguide2/includes/atoms/text/prose_richtext.html"
                ),
            ),
        ],
        verbose_name="Obsah",
        blank=True,
        use_json_field=True,
    )

    ### PANELS

    content_panels = Page.content_panels + [
        FieldPanel("content"),
    ]

    parent_page_types = ["main.MainHomePage"]
    subpage_types = []

    class Meta:
        verbose_name = "Výsledky"


class MainCareersPage(
    ExtendedMetadataPageMixin, SubpageMixin, MetadataPageMixin, PageInMenuMixin, Page
):
    subheading = models.CharField(
        verbose_name="Podtitulek",
        help_text="Text pod hlavním nadpisem stránky",
        max_length=32,
        blank=True,
        null=True,
    )

    perex_col_1 = models.TextField(
        verbose_name="Perex - první sloupec",
        blank=True,
        null=True,
    )
    perex_col_2 = models.TextField(
        verbose_name="Perex - druhý sloupec",
        blank=True,
        null=True,
    )

    content_panels = Page.content_panels + [
        HelpPanel(
            "Pro přidání pracovních nabídek ulož tuto stránku a přidej ji podstránky."
        ),
        FieldPanel("subheading"),
        MultiFieldPanel(
            [
                FieldPanel("perex_col_1", heading="První sloupec"),
                FieldPanel("perex_col_2", heading="Druhý sloupec"),
            ],
            "Perex",
        ),
    ]

    parent_page_types = ["main.MainHomePage"]
    subpage_types = ["main.MainCareerPage"]

    def get_context(self, request, *args, **kwargs) -> dict:
        context = super().get_context(request, *args, **kwargs)

        context["show_closed"] = request.GET.get("show_closed", "false") == "true"

        return context

    def get_career_categories(self) -> list[str]:
        return (
            MainCareerPage.objects.child_of(self)
            .live()
            .distinct("category")
            .values_list("category", flat=True)
            .order_by("category")
            .all()
        )

    def get_career_pages(self, show_closed: bool = False, category: str | None = None):
        filter = models.Q()

        current_date = date.today()

        if not show_closed:
            filter = filter & models.Q(closing_date__gte=current_date)

        if category is not None:
            filter = filter & models.Q(category=category)

        return MainCareerPage.objects.child_of(self).filter(filter).live().all()

    class Meta:
        verbose_name = "Kariéry"


class MainCareerPage(
    ExtendedMetadataPageMixin, SubpageMixin, MetadataPageMixin, PageInMenuMixin, Page
):
    recipient_emails = models.CharField(
        verbose_name="Příjemci emailů o nových přihláškách",
        help_text="Zadej buď jednu adresu, nebo víc, oddělených čárkami.",
        blank=False,
        null=False,
    )

    category = models.CharField(
        verbose_name="Kategorie pracovní pozice",
        help_text="Např. 'Koordinátor/ka', 'Programátor/ka', 'Volební manažer/ka', ...",
        blank=False,
        null=False,
    )

    location = models.CharField(
        verbose_name="Místo výkonu práce",
        help_text="Např. 'Středočeský kraj'",
        max_length=64,
        blank=False,
        null=False,
    )

    time_cost = models.CharField(
        verbose_name="Časová náročnost",
        help_text="Např. '8h denně'",
        max_length=64,
        blank=False,
        null=False,
    )

    employment_relationship = models.CharField(
        verbose_name="Typ smlouvy",
        help_text="Např. 'Rámcová smlouva na dobu určitou'",
        max_length=128,
        blank=False,
        null=False,
    )

    pay_rate = models.CharField(
        verbose_name="Odměna",
        help_text="Např. '300-350 Kč/h'",
        max_length=64,
        blank=False,
        null=False,
    )

    created_date = models.DateField(
        verbose_name="Datum vytvoření", blank=False, null=False, default=date.today
    )

    submission_end_date = models.DateField(
        verbose_name="Datum konce přihlášek",
        blank=False,
        null=False,
    )

    closing_date = models.DateField(
        verbose_name="Datum uzavření",
        blank=False,
        null=False,
    )

    content = RichTextField(
        "Text nabídky", blank=True, null=True, features=RICH_TEXT_DEFAULT_FEATURES
    )

    result = RichTextField(
        "Výsledek výběrového řízení",
        blank=True,
        null=True,
        features=RICH_TEXT_DEFAULT_FEATURES,
    )

    proceedings_url = models.URLField(
        verbose_name="Odkaz na průběh výběrového řízení",
        help_text="Na Redmine, Fóru apod.",
        blank=True,
        null=True,
    )

    content_panels = Page.content_panels + [
        MultiFieldPanel(
            [
                FieldPanel("created_date"),
                FieldPanel("submission_end_date"),
                FieldPanel("closing_date"),
            ],
            "Datumy",
        ),
        FieldPanel("recipient_emails"),
        FieldPanel("category"),
        FieldPanel("location"),
        FieldPanel("time_cost"),
        FieldPanel("employment_relationship"),
        FieldPanel("pay_rate"),
        FieldPanel("proceedings_url"),
        FieldPanel("content"),
        FieldPanel("result"),
    ]

    parent_page_types = ["main.MainCareersPage"]

    def serve(self, request):
        if is_ratelimited(
            request, group="career_submissions", key="ip", rate="2/m", method="POST"
        ):
            raise PermissionDenied("Rate limit exceeded")

        form = None
        current_time = datetime.now()
        current_date = current_time.date()

        if (
            request.method == "POST"
            and self.closing_date >= current_date
            and self.submission_end_date >= current_date
        ):
            form = CareerSubmissionForm(request.POST, request.FILES)

            if form.is_valid():
                other_files_names = ""

                for file in form.cleaned_data["other_files"]:
                    other_files_names += f"        - {file.name}\n"

                recipient_email = EmailMessage(
                    # Subject
                    f"Potvrzení přihlášky k výběrovému řízení {self.title}",
                    # Message
                    f"""
Dobrý den,

potvrzujeme přijetí Vaší přihlášky k výběrovému řízení '{self.title}'.
Budeme vás co nejdříve kontaktovat s dalšími informacemi.

V případě nejasností můžete kontaktovat kancelář, kontakty lze nalézt zde: https://wiki.pirati.cz/kas/start

Děkujeme,
Pirátská strana
""",
                    # From email
                    "vyberka@pirati.cz",
                    # To email
                    [form.cleaned_data["email"]],
                )

                administrator_email = EmailMessage(
                    # Subject
                    f"Nová přihláška k výběrovému řízení {self.title} - {form.cleaned_data['name']} {form.cleaned_data['surname']}",
                    # Message
                    (
                        f"""
K výběrovému řízení {self.title} se {current_time} přihlásil nový zájemce.

Vyplněné údaje:

    Jméno: {form.cleaned_data['name']}
    Příjmení: {form.cleaned_data['surname']}
    E-mail: {form.cleaned_data['email']}
    Telefon: {form.cleaned_data['phone']}
    Chce posílat další nabídky: {'Ano' if form.cleaned_data['other_offers_agreement'] else 'Ne'}
    Vlastní text: {form.cleaned_data['own_text'] if form.cleaned_data['own_text'] else '(nevyplněn)'}

CV, motivační dopis a ostatní soubory jsou v přílohách. Názvy souborů:

    CV: {form.cleaned_data["cv_file"].name}
    Mot. dopis: {form.cleaned_data["cover_letter_file"].name}
    Ostatní soubory:
{other_files_names}

Při otevírání souborů buďte opatrní, virový sken proběhl, ale nemusí být přesný!
                        """
                    ),
                    # From email
                    "vyberka@pirati.cz",
                    # Recipient list
                    self.recipient_emails.split(","),
                )

                form.cleaned_data["cv_file"].seek(0)
                administrator_email.attach(
                    form.cleaned_data["cv_file"].name,
                    form.cleaned_data["cv_file"].read(),
                    form.cleaned_data["cv_file"].content_type,
                )

                form.cleaned_data["cover_letter_file"].seek(0)
                administrator_email.attach(
                    form.cleaned_data["cover_letter_file"].name,
                    form.cleaned_data["cover_letter_file"].read(),
                    form.cleaned_data["cover_letter_file"].content_type,
                )

                for file in form.cleaned_data["other_files"]:
                    file.seek(0)
                    administrator_email.attach(
                        file.name, file.read(), file.content_type
                    )

                sent_successfully = (
                    administrator_email.send() and recipient_email.send()
                )

                if sent_successfully:
                    messages.add_message(
                        request, messages.SUCCESS, "Přihláška odeslána."
                    )
                else:
                    messages.add_message(
                        request,
                        messages.ERROR,
                        "Odeslání přihlášky selhalo. Zkuste to znovu.",
                    )
            else:
                errors = ""

                for error_val in form.errors.values():
                    errors += f"{error_val.as_text()}\n"

                messages.add_message(
                    request,
                    messages.ERROR,
                    f"""
Odeslání přihlášky selhalo:
{errors}
""",
                )

        # Recreate form either way, since we don't want it to be prepopulated with data.
        form = CareerSubmissionForm()

        return render(
            request,
            self.template,
            {
                "page": self,
                "self": self,
                "form": form,
                "current_date": date.today(),
            },
        )

    class Meta:
        verbose_name = "Pracovní nabídka"


class MainSearchPage(MainSearchPageMixin):
    parent_page_types = ["main.MainHomePage"]
    subpage_types = []

    @property
    def searchable_models(self) -> list:
        return [
            MainArticlePage,
            MainPersonPage,
            MainSimplePage,
        ]