from django import forms
from django.db import models
from django.db.models import Min, Q, UniqueConstraint
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from grapple.helpers import register_query_field, register_singular_query_field
from grapple.models import (
    GraphQLBoolean,
    GraphQLCollection,
    GraphQLForeignKey,
    GraphQLImage,
    GraphQLInt,
    GraphQLStreamfield,
    GraphQLString,
)
from modelcluster.fields import ParentalKey, ParentalManyToManyField
from modelcluster.models import ClusterableModel
from wagtail.admin.panels import (
    FieldPanel,
    FieldRowPanel,
    HelpPanel,
    InlinePanel,
    MultiFieldPanel,
    MultipleChooserPanel,
    TitleFieldPanel,
)
from wagtail.models import Orderable, Page, PageManager, PageQuerySet
from wagtail.search import index
from wagtail.snippets.models import register_snippet

from associations.widgets import AssociationChooserWidget
from dnscms.fields import CommonStreamField
from venues.models import VenuePage

ALL_PIGS = [
    ("logo", "Logogrisen"),
    ("music", "Musikergrisen"),
    ("drink", "Drikkegrisen"),
    ("dance", "Dansegrisen"),
    ("point", "Pekegrisen"),
    ("student", "Studentgrisen"),
    ("listen", "Lyttegrisen"),
    ("guard", "Vaktgrisen"),
    ("key", "Nøkkelgrisen"),
    ("chill", "Liggegrisen"),
    ("peek", "Tittegrisen"),
]


@register_singular_query_field("eventIndex")
class EventIndex(Page):
    max_count = 1
    subpage_types = ["events.EventPage"]

    def future_events(self, info, **kwargs):
        return EventPage.objects.future().order_by("next_occurrence")

    graphql_fields = [
        GraphQLCollection(
            GraphQLForeignKey,
            "future_events",
            "events.EventPage",
            required=True,
            item_required=True,
            is_queryset=True,
        ),
    ]

    search_fields = []


@register_snippet
@register_query_field("eventCategory", "eventCategories")
class EventCategory(models.Model):
    name = models.CharField(
        max_length=100,
        null=False,
        blank=False,
    )
    slug = models.SlugField(
        verbose_name=_("slug"),
        max_length=255,
        help_text=_("The name of the category as it will appear in URLs."),
    )
    show_in_filters = models.BooleanField(
        default=False, help_text="Skal denne kategorien være mulig å filtrere på i programmet?"
    )

    PIG_CHOICES = [
        ("", "Ingen"),
    ] + ALL_PIGS

    pig = models.CharField(
        max_length=32,
        choices=PIG_CHOICES,
        default="",
        blank=True,
        help_text="Standardgris for arrangementer av denne typen.",
    )

    panels = [
        TitleFieldPanel("name"),
        FieldPanel("slug"),
        FieldPanel("show_in_filters"),
        FieldPanel("pig", heading="Gris"),
    ]

    graphql_fields = [
        GraphQLString("name", required=True),
        GraphQLString("slug", required=True),
        GraphQLBoolean("show_in_filters", required=True),
        GraphQLString("pig", required=True),
    ]

    class Meta:
        verbose_name = "Event category"
        verbose_name_plural = "Event categories"
        ordering = ["name"]

    def __str__(self):
        return self.name


class EventOrganizerLink(Orderable):
    event = ParentalKey(
        "events.EventPage", on_delete=models.CASCADE, related_name="organizer_links"
    )
    organizer = models.ForeignKey(
        "events.EventOrganizer",
        on_delete=models.PROTECT,
        related_name="organized_events",
        help_text="",
    )

    panels = [FieldPanel("organizer", heading="", help_text="")]

    graphql_fields = [
        GraphQLForeignKey("organizer", "events.EventOrganizer"),
    ]

    def __str__(self):
        return f"{self.organizer.name}"

    class Meta:
        verbose_name = "Arrangør"
        verbose_name_plural = "Arrangører"
        constraints = [
            UniqueConstraint(
                "event", "organizer", name="event_organizer_link_event_organizer_unique"
            )
        ]


@register_snippet
@register_query_field("eventOrganizer", "eventOrganizers")
class EventOrganizer(ClusterableModel):
    name = models.CharField(
        max_length=100,
        null=False,
        blank=False,
    )
    slug = models.SlugField(
        verbose_name=_("slug"),
        max_length=255,
        help_text=_("The name of the organizer as it will appear in URLs."),
    )

    association = models.ForeignKey(
        "associations.AssociationPage",
        null=True,
        blank=True,
        on_delete=models.PROTECT,
        related_name="organizers",
        help_text="Om en samfundsforening eller et utvalg står bak, velg det her.",
    )

    external_url = models.URLField(
        blank=True,
        max_length=512,
        help_text="Lenke til nettstedet til ekstern arrangør",
    )

    panels = [
        TitleFieldPanel("name"),
        FieldPanel("slug"),
        FieldPanel(
            "association",
            widget=AssociationChooserWidget(linked_fields={"association": "#id_association"}),
            heading="Intern arrangør",
        ),
        MultiFieldPanel(
            heading="Ekstern arrangør",
            children=[
                FieldPanel(
                    "external_url",
                    heading="Nettsted",
                    help_text="La denne stå tom om arrangøren finnes i lista over.",
                ),
            ],
        ),
    ]

    graphql_fields = [
        GraphQLString("name", required=True),
        GraphQLString("slug", required=True),
        GraphQLForeignKey("association", "associations.AssociationPage", required=False),
        GraphQLString("external_url"),
    ]

    class Meta:
        verbose_name = "Event organizer"
        verbose_name_plural = "Event organizers"
        ordering = ["name"]

    def __str__(self):
        return self.name


class EventPageQuerySet(PageQuerySet):
    def future(self):
        today = timezone.localtime(timezone.now()).date()
        next_occurrence = Min("occurrences__start", filter=Q(occurrences__start__gte=today))
        return self.filter(occurrences__start__gte=today).annotate(next_occurrence=next_occurrence)


EventPageManager = PageManager.from_queryset(EventPageQuerySet)


class EventPage(Page):
    subpage_types = []
    parent_page_types = ["events.EventIndex"]
    show_in_menus = False

    objects = EventPageManager()

    featured_image = models.ForeignKey(
        "images.CustomImage",
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name="+",
        help_text=(
            "Velg et bilde til bruk i programmet og andre visningsflater. "
            "Bør være et bilde eller en illustrasjon uten tekst "
            "– ikke gjenbruk et Facebook-cover ukritisk!"
        ),
    )

    body = CommonStreamField

    categories = ParentalManyToManyField(
        "events.EventCategory",
        blank=True,
    )

    organizers = models.ManyToManyField(
        "events.EventOrganizer", through="events.EventOrganizerLink"
    )

    PIG_CHOICES = [
        ("", "Ingen"),
        ("automatic", "Automatisk"),
    ] + ALL_PIGS

    pig = models.CharField(
        max_length=32,
        choices=PIG_CHOICES,
        default="automatic",
        blank=True,
        help_text=(
            "Grisen som henger på arrangementssiden. "
            "Automatisk fører til at en velges basert på arrangementets kategori."
        ),
    )

    ticket_url = models.URLField(
        blank=True,
        max_length=512,
        help_text="Lenke direkte til billettkjøp, f.eks. TicketCo eller Ticketmaster",
    )
    facebook_url = models.URLField(
        blank=True,
        max_length=512,
        help_text="Lenke direkte til arrangementet på Facebook",
    )

    free = models.BooleanField(null=False, default=False)
    price_regular = models.IntegerField(null=True, blank=True)
    price_student = models.IntegerField(null=True, blank=True)
    price_member = models.IntegerField(null=True, blank=True)

    ticket_panels = [
        FieldPanel("free", heading="Gratis", help_text="Er dette arrangementet gratis for alle?"),
        MultiFieldPanel(
            children=[
                FieldRowPanel(
                    children=[
                        FieldPanel("price_regular", heading="Ordinær pris"),
                        FieldPanel("price_student", heading="Pris for studenter"),
                        FieldPanel("price_member", heading="Pris for medlemmer av DNS"),
                    ],
                    help_text="",
                ),
                HelpPanel(content="La alle prisfeltene stå tomme om arrangementet er gratis."),
            ],
            attrs={"id": "specific_pricing_panel"},
        ),
        FieldPanel("ticket_url", heading="Billettkjøpslenke"),
    ]

    content_panels = Page.content_panels + [
        FieldPanel("featured_image"),
        FieldPanel("body"),
        FieldPanel("categories", widget=forms.CheckboxSelectMultiple),
        MultiFieldPanel(
            heading="Arrangører",
            children=[
                HelpPanel(
                    content=("Hvem står bak arrangementet?"),
                ),
                MultipleChooserPanel(
                    "organizer_links", chooser_field_name="organizer", min_num=1, label="Arrangør"
                ),
            ],
        ),
        FieldPanel("pig", heading="Gris"),
        FieldPanel(
            "facebook_url",
            heading="Facebook-lenke",
            help_text="Lenke direkte til arrangementet på Facebook.",
        ),
        MultiFieldPanel(heading="Priser og billettkjøp", children=ticket_panels),
        MultiFieldPanel(
            heading="Dato, tid og lokale",
            children=[
                HelpPanel(
                    content=(
                        "Om arrangementet går over flere dager, "
                        "legg inn hver dag som en egen forekomst."
                    ),
                ),
                InlinePanel("occurrences", min_num=1, label="Forekomst"),
            ],
        ),
    ]

    graphql_fields = [
        GraphQLImage("featured_image"),
        GraphQLStreamfield("body"),
        GraphQLString("pig"),
        GraphQLString("ticket_url"),
        GraphQLString("facebook_url"),
        GraphQLBoolean("free"),
        GraphQLInt("price_regular"),
        GraphQLInt("price_student"),
        GraphQLInt("price_member"),
        GraphQLCollection(
            GraphQLForeignKey,
            "categories",
            "events.EventCategory",
            required=True,
            item_required=True,
        ),
        GraphQLCollection(
            GraphQLForeignKey,
            "occurrences",
            "events.EventOccurrence",
            required=True,
            item_required=True,
        ),
        GraphQLCollection(
            GraphQLForeignKey,
            "organizers",
            "events.EventOrganizer",
            required=True,
            item_required=True,
        ),
    ]

    search_fields = Page.search_fields + [index.SearchField("body")]

    def clean(self):
        super().clean()

        # remove duped organizers based on name
        organizers = [x.organizer.name for x in self.organizer_links.all()]
        if len(organizers) != len(set(organizers)):
            seen_organizers = set()
            for link in self.organizer_links.all():
                if link.organizer.name in seen_organizers:
                    self.organizer_links.remove(link)
                else:
                    seen_organizers.add(link.organizer.name)

        # if the event is free, all specific pricing is unset
        if self.free:
            self.price_regular = None
            self.price_student = None
            self.price_member = None


class EventOccurrence(Orderable):
    event = ParentalKey(EventPage, on_delete=models.CASCADE, related_name="occurrences")
    start = models.DateTimeField()
    end = models.DateTimeField(null=True, blank=True)
    venue = models.ForeignKey(
        VenuePage, on_delete=models.PROTECT, related_name="event_occurrences"
    )

    panels = [
        FieldRowPanel(
            children=[
                FieldPanel("start", heading="Start"),
                FieldPanel("end", heading="Slutt"),
            ],
        ),
        FieldPanel("venue", heading="Lokale"),
    ]

    graphql_fields = [
        GraphQLString("start", required=True),
        GraphQLString("end"),
        GraphQLForeignKey("venue", "venues.VenuePage"),
    ]

    def __str__(self):
        return f"{self.start}--{self.end}"

    class Meta:
        verbose_name = "Forekomst"
        verbose_name_plural = "Forekomster"


sample_legacy_event_json = """
{
  "id": 64573,
  "date": "2023-12-27T11:28:34",
  "date_gmt": "2023-12-27T10:28:34",
  "guid": {
    "rendered": "https://studentersamfundet.no/?post_type=event&#038;p=64573"
  },
  "modified": "2023-12-27T11:44:11",
  "modified_gmt": "2023-12-27T10:44:11",
  "slug": "quiz-147-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-3-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-3-2-2-2-2-2-2-2-2-2-2-2-2-2",
  "status": "publish",
  "type": "event",
  "link": "https://studentersamfundet.no/arrangement/quiz-147-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-3-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-2-3-2-2-2-2-2-2-2-2-2-2-2-2-2/",
  "title": {
    "rendered": "QUIZ",
    "decoded": "QUIZ"
  },
  "content": {
    "rendered": "\n<p>Det Norske Studentersamfund inviterer til quiz hver tirsdag kl. 19:00.</p>\n\n\n\n<p>Vi serverer 50 spørsmål som kan spenne seg fra one hit wonders fra 80-tallet, universets uendelighet, dyrelivets merkverdigheter og mye, mye mer!</p>\n\n\n\n<p>Quiz på Chateau Neuf er åpent for alle. Vinnere og &#8220;lucky losers&#8221; vil bli utnevnt hver kveld. Lag som er over seks personer er tillatt, men da trekkes dere for  ett poeng per deltaker per runde.</p>\n\n\n\n<p>For de som ønsker å være med på sammenlagtkonkurransen for høsten vil den regnes ut for de tolv beste prestasjonene laget leverer. Så det vil fremdeles være god sjanse for å vinne sammenlagt selv dere må droppe en quiz eller to for eksamener eller andre forpliktelser.</p>\n\n\n\n<p>Velkommen quizglade mennesker!</p>\n\n\n\n<p>Gratis inngang!</p>\n",
    "protected": false
  },
  "excerpt": {
    "rendered": "<p>Det Norske Studentersamfund inviterer til quiz hver tirsdag kl. 19:00. Vi serverer 50 spørsmål som kan spenne seg fra one hit wonders fra 80-tallet, universets uendelighet, dyrelivets merkverdigheter og mye, mye mer! Quiz på Chateau Neuf er åpent for alle. Vinnere og &#8220;lucky losers&#8221; vil bli utnevnt hver kveld. Lag som er over seks personer [&hellip;]</p>\n",
    "protected": false
  },
  "author": 2150,
  "featured_media": 64585,
  "template": "",
  "meta": [],
  "event_types": [13],
  "event_organizers": [390, 322],
  "facebook_url": "https://fb.me/e/2RDR5pZdr",
  "ticket_url": "",
  "price_regular": "",
  "price_member": "",
  "start_time": "2024-05-07T17:00:00+00:00",
  "end_time": "2024-05-07T20:00:00+00:00",
  "venue": "Glassbaren",
  "venue_id": "55063",
  "thumbnail": {
    "thumbnail": "https://studentersamfundet.no/wp/wp-content/uploads/2023/12/quiz-header-1-150x150.png",
    "medium": "https://studentersamfundet.no/wp/wp-content/uploads/2023/12/quiz-header-1-300x169.png",
    "medium_large": "https://studentersamfundet.no/wp/wp-content/uploads/2023/12/quiz-header-1-768x433.png",
    "large": "https://studentersamfundet.no/wp/wp-content/uploads/2023/12/quiz-header-1-1280x720.png",
    "1536x1536": "https://studentersamfundet.no/wp/wp-content/uploads/2023/12/quiz-header-1-1536x865.png",
    "2048x2048": "https://studentersamfundet.no/wp/wp-content/uploads/2023/12/quiz-header-1.png",
    "four-column": "https://studentersamfundet.no/wp/wp-content/uploads/2023/12/quiz-header-1-393x342.png",
    "six-column": "https://studentersamfundet.no/wp/wp-content/uploads/2023/12/quiz-header-1-608x342.png",
    "extra-large": "https://studentersamfundet.no/wp/wp-content/uploads/2023/12/quiz-header-1-1600x901.png",
    "newsletter-half": "https://studentersamfundet.no/wp/wp-content/uploads/2023/12/quiz-header-1-320x190.png",
    "newsletter-third": "https://studentersamfundet.no/wp/wp-content/uploads/2023/12/quiz-header-1-213x126.png",
    "featured": "https://studentersamfundet.no/wp/wp-content/uploads/2023/12/quiz-header-1-1200x480.png"
  },
  "_links": {
    "self": [
      {
        "href": "https://studentersamfundet.no/wp-json/wp/v2/events/64573"
      }
    ],
    "collection": [
      {
        "href": "https://studentersamfundet.no/wp-json/wp/v2/events"
      }
    ],
    "about": [
      {
        "href": "https://studentersamfundet.no/wp-json/wp/v2/types/event"
      }
    ],
    "author": [
      {
        "embeddable": true,
        "href": "https://studentersamfundet.no/wp-json/wp/v2/users/2150"
      }
    ],
    "version-history": [
      {
        "count": 1,
        "href": "https://studentersamfundet.no/wp-json/wp/v2/events/64573/revisions"
      }
    ],
    "predecessor-version": [
      {
        "id": 64574,
        "href": "https://studentersamfundet.no/wp-json/wp/v2/events/64573/revisions/64574"
      }
    ],
    "wp:featuredmedia": [
      {
        "embeddable": true,
        "href": "https://studentersamfundet.no/wp-json/wp/v2/media/64585"
      }
    ],
    "wp:attachment": [
      {
        "href": "https://studentersamfundet.no/wp-json/wp/v2/media?parent=64573"
      }
    ],
    "wp:term": [
      {
        "taxonomy": "event_type",
        "embeddable": true,
        "href": "https://studentersamfundet.no/wp-json/wp/v2/event_types?post=64573"
      },
      {
        "taxonomy": "event_organizer",
        "embeddable": true,
        "href": "https://studentersamfundet.no/wp-json/wp/v2/event_organizers?post=64573"
      }
    ],
    "curies": [
      {
        "name": "wp",
        "href": "https://api.w.org/{rel}",
        "templated": true
      }
    ]
  }
}

"""
