from django.contrib.auth import get_user_model
from django.core.validators import RegexValidator
from django.db import models
from django.http import HttpResponsePermanentRedirect
from django.shortcuts import reverse
from django.urls import NoReverseMatch
from django.utils.translation import gettext_lazy as _
from wagtailmetadata.models import MetadataPageMixin

from wagtail import blocks
from wagtail.admin.panels import (
    FieldPanel,
    MultiFieldPanel,
    PageChooserPanel,
)
from wagtail.blocks import RichTextBlock
from wagtail.contrib.settings.models import BaseSiteSetting, register_setting
from wagtail.fields import RichTextField, StreamField
from wagtail.images import get_image_model_string
from wagtail.images.blocks import ImageChooserBlock
from wagtail.images.widgets import AdminImageChooser
from wagtail.models import Page
from wagtail.search import index

from ocyan.main.loading import get_ocyan_class

from .block_plugin import get_extra_ocyan_settings_blocks
from .blocks import (
    AboutUsBlock,
    HeadedPagelistBlock,
    HeadedRichTextBlock,
    ImageLinkBlock,
    LinkBlock,
)
from .localization import localize_internal_path
from .middleware import get_current_request, get_current_site

OcyanPage = get_ocyan_class("wagtail_i18n.compat", "Page")
I18nPageMixin = get_ocyan_class("wagtail_i18n.mixins", "I18nPageMixin")

IMAGE_MODEL = get_image_model_string()


class MenuLink(Page):
    subpage_types = ["ocyan_plugin_wagtail.MenuLink"]

    link = models.CharField(
        max_length=512, validators=[RegexValidator(regex=r"(?:[/?#][^\s]*)?")]
    )
    show_in_menus_default = True

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

    preview_modes = []

    # pylint: disable=W0702
    def get_link(self):
        request = get_current_request()
        if ":" in self.link:
            try:
                resolved = reverse(self.link)
                return localize_internal_path(
                    resolved,
                    request=request,
                    language_code=getattr(self.locale, "language_code", None),
                )
            except NoReverseMatch:
                pass

        return localize_internal_path(
            self.link,
            request=request,
            language_code=getattr(self.locale, "language_code", None),
        )

    def get_url_parts(self, request=None):
        return (None, "", self.get_link())

    def set_url_path(self, parent):
        self.url_path = self.get_link()
        return self.get_link()

    def get_sitemap_urls(self, request=None):
        return []

    def serve(self, request, *args, **kwargs):
        redirect_path = request.build_absolute_uri(self.get_link())
        return HttpResponsePermanentRedirect(redirect_path)

    page_description = _("Adds button to the menu that links to a chosen URL.")

    class Meta:
        verbose_name = _("Menu link page")
        verbose_name_plural = _("Menu link pages")


class AbstractBasePage(I18nPageMixin, MetadataPageMixin, OcyanPage):
    # This should be seen as an abstract page, but we'd like these fields in
    # a seperate table. This makes migrations show up in this package.
    is_creatable = False  # This MUST be False.

    meta_keywords = models.TextField("Meta Keywords", blank=True, null=True)

    canonical_url = models.URLField(
        blank=True,
        null=True,
        max_length=255,
        verbose_name=_("Canonical URL"),
        help_text=_("Leave blank to use the page's URL."),
    )

    promote_panels = OcyanPage.promote_panels + [
        FieldPanel("meta_keywords"),
        FieldPanel("canonical_url"),
        FieldPanel("search_image", widget=AdminImageChooser),
    ]

    @property
    def meta_description(self):
        # We used to have a meta_description field but this has been removed once
        # wagtail added a field for this to the page model. Some templates might still use
        # .meta_description, so that's why this property is here.
        return self.search_description

    @property
    def search_title(self):
        return self.title

    search_fields = OcyanPage.search_fields + [
        index.SearchField(
            "search_title",
            es_extra={
                "analyzer": "title_analyzer",
                "search_analyzer": "lowercasewhitespace",
                "fields": {
                    "reversed": {
                        "type": "text",
                        "analyzer": "reversed_title_analyzer",
                        "search_analyzer": "lowercasewhitespace",
                    }
                },
            },
        ),
    ]


_original_get_url = Page.get_url


def patched_get_url(self, request=None, current_site=None):
    request = request or get_current_request()
    current_site = current_site or get_current_site()
    return _original_get_url(self, request, current_site)


Page.get_url = patched_get_url
Page.url = property(Page.get_url)


@register_setting
class OcyanSettings(BaseSiteSetting):
    # Social media
    facebook_url = models.URLField(help_text=_("Your Facebook page URL"), blank=True)
    twitter_url = models.URLField(help_text=_("Your Twitter url"), blank=True)
    instagram_url = models.URLField(help_text=_("Your Instagram url"), blank=True)
    linkedin_url = models.URLField(help_text=_("Your LinkedIn url"), blank=True)
    youtube_url = models.URLField(
        help_text=_("Your YouTube channel or user account URL"), blank=True
    )
    pinterest_url = models.URLField(help_text=_("Your pinterest url"), blank=True)
    tiktok_url = models.URLField(help_text=_("Your TikTok url"), blank=True)

    # Contact details
    phone_number = models.CharField(max_length=255, blank=True)
    email_address = models.EmailField(max_length=255, blank=True)

    # Legal
    terms = models.ForeignKey(
        "wagtailcore.Page",
        verbose_name=_("Terms and conditions page"),
        on_delete=models.SET_NULL,
        blank=True,
        null=True,
    )

    # Delivery
    delivery_time_text = RichTextField(
        _("Delivery time explanation"), blank=True, null=True
    )
    delivery_time_days = models.PositiveIntegerField(
        _("Upper limit of standard delivery time in days"), blank=True, null=True
    )

    # General page
    logo = models.ForeignKey(
        IMAGE_MODEL, on_delete=models.PROTECT, related_name="+", null=True
    )
    logo_alt = models.CharField(max_length=255, blank=True)

    footer = StreamField(
        [
            ("about_us", AboutUsBlock()),
            ("text", HeadedRichTextBlock()),
            ("page_list", HeadedPagelistBlock()),
        ]
        + get_extra_ocyan_settings_blocks(),
        default=[],
        use_json_field=True,
    )
    mini_footer = StreamField(
        [("text", RichTextBlock())], default=[], use_json_field=True
    )

    header_content = StreamField(
        [
            ("text", RichTextBlock()),
            ("image", ImageChooserBlock()),
            ("image_link", ImageLinkBlock()),
        ]
        + get_extra_ocyan_settings_blocks(),
        blank=True,
        use_json_field=True,
    )

    promo_header = StreamField(
        [
            ("text", RichTextBlock()),
            ("image", ImageChooserBlock()),
            (
                "TextSlider",
                blocks.ListBlock(blocks.StructBlock([("text", blocks.CharBlock())])),
            ),
        ],
        blank=True,
        help_text="Mobile only",
        use_json_field=True,
    )

    # Socialbar settings
    social_links = StreamField(
        [("link", LinkBlock())],
        verbose_name="Socialbar links",
        blank=True,
        use_json_field=True,
    )
    whatsapp_url = models.URLField(help_text=_("Your Whatsapp url"), blank=True)
    invoice_footer_text = RichTextField(
        _("Invoice footer text"),
        blank=True,
        null=True,
        help_text=_("This text will be displayed at the bottom of your invoice"),
    )

    seo_title = models.CharField(max_length=255, blank=True, verbose_name=_("Title"))
    seo_description = models.CharField(
        max_length=255, blank=True, verbose_name=_("Description")
    )

    panels = [
        MultiFieldPanel(
            [FieldPanel("logo", widget=AdminImageChooser), FieldPanel("logo_alt")],
            heading=_("logo"),
        ),
        MultiFieldPanel(
            [FieldPanel("phone_number"), FieldPanel("email_address")],
            heading=_("Contact details"),
        ),
        PageChooserPanel("terms"),
        MultiFieldPanel(
            [FieldPanel("delivery_time_text"), FieldPanel("delivery_time_days")],
            heading=_("Delivery time"),
        ),
        MultiFieldPanel(
            [FieldPanel("seo_title"), FieldPanel("seo_description")],
            heading=_("SEO settings for the root category"),
        ),
        MultiFieldPanel(
            [
                FieldPanel("facebook_url"),
                FieldPanel("twitter_url"),
                FieldPanel("instagram_url"),
                FieldPanel("linkedin_url"),
                FieldPanel("youtube_url"),
                FieldPanel("pinterest_url"),
                FieldPanel("tiktok_url"),
            ],
            heading=_("Social media"),
        ),
        MultiFieldPanel(
            [FieldPanel("whatsapp_url"), FieldPanel("social_links")],
            heading=_("Social bar"),
        ),
        FieldPanel("footer"),
        FieldPanel("mini_footer"),
        FieldPanel("header_content"),
        FieldPanel("promo_header"),
        FieldPanel("invoice_footer_text"),
    ]

    @property
    def terms_and_conditions(self):
        if self.terms is not None:
            # pylint: disable=no-member
            return self.terms.url
        return "/disclaimer/"

    class Meta:
        verbose_name = _("Site Settings")


class Account(get_user_model()):
    """
    Account is a proxy model for user and has a Wagtail chooser attached to it for easy searching and selecting users in the admin
    """

    def get_most_descriptive_name(self):
        if self.is_staff:
            candidates = [self.get_full_name(), self.get_username(), self.email]
        else:
            candidates = [self.get_full_name(), self.email, self.get_username()]

        for candidate in candidates:
            if candidate.strip():
                return candidate

    def __str__(self):
        return "%s - %s" % (self.get_most_descriptive_name(), self.email)

    autocomplete_search_field = "email"

    def autocomplete_label(self):
        return str(self)

    class Meta:
        proxy = True
        verbose_name = _("User")
