from datetime import datetime

from django.db import models
from django.utils.translation import gettext_lazy as _

from ckeditor.fields import RichTextField
from django_iban.fields import IBANField

from aleksis.core.mixins import ExtensibleModel
from aleksis.core.models import Group, Person

from .util import generate_code


class FeedbackAspect(ExtensibleModel):
    aspect = models.CharField(max_length=100)

    def __str__(self) -> str:
        return self.aspect


class Event(ExtensibleModel):
    # Event details
    display_name = models.CharField(verbose_name=_("Display name"), max_length=255)
    linked_group = models.OneToOneField(
        Group, on_delete=models.CASCADE, verbose_name=_("Group"), related_name="linked_event"
    )
    description = models.CharField(max_length=500, verbose_name=_("Description"))
    published = models.BooleanField(default=False, verbose_name=_("Publish"))
    place = models.CharField(max_length=50, verbose_name="Place")

    # Date details
    date_event = models.DateField(verbose_name=_("Date of event"))
    date_registration = models.DateField(verbose_name=_("Registration deadline"))
    date_retraction = models.DateField(verbose_name=_("Retraction deadline"))

    # Other details
    cost = models.IntegerField(verbose_name=_("Cost in €"))
    max_participants = models.PositiveSmallIntegerField(verbose_name=_("Maximum participants"))
    information = RichTextField(verbose_name=_("Information about the event"))

    # Feedback
    feedback_aspects = models.ManyToManyField(
        FeedbackAspect,
        verbose_name=_("Feedback aspects"),
        related_name="event",
        null=True,
        blank=True,
    )

    def __str__(self) -> str:
        return self.display_name

    def can_register(self, request=None):
        now = datetime.today().date()

        if request and request.user.is_authenticated:
            if request.user.person in self.linked_group.members.all():
                return False

            if (
                Voucher.objects.filter(event=self, person=request.user.person, used=False).count()
                > 0
            ):
                return True

        if self.linked_group.members.count() >= self.max_participants:
            return False

        if self.date_registration:
            return self.date_registration >= now
        return self.date_event > now

    @property
    def booked_percentage(self):
        return self.linked_group.members.count() / self.max_participants * 100

    @property
    def members_persons(self):
        return self.linked_group.members.all()

    @property
    def owners_persons(self):
        return self.linked_group.owners.all()


class EventFeedback(ExtensibleModel):

    COMMENT_CHOICES = [
        ("first", _("Only first name")),
        ("first_age", _("First name and age")),
        ("first_last_age", _("First name, last name and age")),
    ]

    LICENCE_CHOICES = [
        ("CC-BY-4.0+", _("Creative Commons with attribution, 4.0 or later")),
        (
            "CC-BY-SA-4.0+",
            _(
                "Creative Commons with attribution and distribution only"
                "under the same conditions, 4.0 or later"
            ),
        ),
    ]

    event = models.ForeignKey(
        Event, on_delete=models.CASCADE, verbose_name=_("Event"), related_name="feedback"
    )
    person = models.ForeignKey(
        Person, on_delete=models.CASCADE, verbose_name=_("Person"), related_name="feedback"
    )

    comment_private = models.TextField(verbose_name=_("Private comment"), blank=True)
    comment_public = models.TextField(verbose_name=_("Public comment"), blank=True)
    comment_public_info = models.CharField(
        choices=COMMENT_CHOICES, verbose_name=_("Information in the comment"), max_length=255
    )

    photos = models.ImageField(verbose_name=_("Photos"), upload_to="feedback/", blank=True)
    photos_licence = models.CharField(
        choices=LICENCE_CHOICES, verbose_name=_("Photo licence"), max_length=255
    )

    class Meta:
        verbose_name = _("Event feedback")
        verbose_name_plural = _("Event feedbacks")
        constraints = [
            models.UniqueConstraint(
                fields=["person", "event"], name="unique_person_feedback_per_event"
            )
        ]


class Voucher(ExtensibleModel):
    class Meta:
        verbose_name = _("Vouchers")
        verbose_name_plural = _("Vouchers")

    code = models.CharField(max_length=8, blank=True, default="")
    event = models.ForeignKey(
        Event,
        related_name="vouchers",
        verbose_name=_("Event"),
        on_delete=models.CASCADE,
        null=True,
    )
    person = models.ForeignKey(
        Person,
        related_name="vouchers",
        verbose_name=_("Person"),
        on_delete=models.CASCADE,
    )
    discount = models.IntegerField(default=100)

    used = models.BooleanField(default=False)
    used_person_uid = models.ForeignKey(
        Person,
        on_delete=models.CASCADE,
        verbose_name=_("Used by"),
        related_name="used_vouchers",
        null=True,
    )
    deleted = models.BooleanField(default=False)

    def __str__(self) -> str:
        return self.code

    def save(self, *args, **kwargs):
        if not self.code:
            self.code = generate_code()
        super().save(*args, **kwargs)


class EventRegistration(ExtensibleModel):

    event = models.ForeignKey(Event, on_delete=models.CASCADE, verbose_name=_("Event"))
    person = models.ForeignKey(Person, on_delete=models.CASCADE, verbose_name=_("Person"))
    date_registred = models.DateTimeField(auto_now_add=True, verbose_name=_("Registration date"))

    comment = models.TextField(verbose_name=_("Comment / remarks"), blank=True, default="")
    medical_information = models.TextField(
        verbose_name=_("Medical information / intolerances"), blank=True, default=""
    )
    channel = models.CharField(verbose_name=_("Channel"), max_length=255, blank=True, default="")
    voucher = models.ForeignKey(
        Voucher,
        on_delete=models.CASCADE,
        verbose_name=_("Voucher"),
        blank=True,
        null=True,
    )
    donation = models.PositiveIntegerField(verbose_name=_("Donation"), blank=True, null=True)

    accept_sepa = models.BooleanField(verbose_name=_("SEPA direct debit"))
    iban = IBANField(
        verbose_name=_("IBAN (for SEPA direct debit)"),
        enforce_database_constraint=True,
        null=True,
        blank=True,
    )

    accept_terms = models.BooleanField(verbose_name=_("Delcaration of consent by parents"))
    accept_data = models.BooleanField(verbose_name=_("Declaration of consent data protection"))
    accept_general_terms = models.BooleanField(
        verbose_name=_("Declatation of consent terms and condition")
    )

    def __str__(self) -> str:
        return f"{self.event}, {self.person.first_name} {self.person.last_name}"

    class Meta:
        verbose_name = _("Event registration")
        verbose_name_plural = _("Event registrations")
        constraints = [
            models.UniqueConstraint(
                fields=["person", "event"], name="unique_person_registration_per_event"
            )
        ]