from datetime import date

import icalendar
from django.core.exceptions import ValidationError
from django.db import models
from django.db.models import Q
from django.utils.timezone import datetime
from django.utils.translation import gettext_lazy as _


class SpecialPeriod(models.Model):

    name = models.CharField(verbose_name=_("Period name"), max_length=255)
    start_date = models.DateField(verbose_name=_("Start day"))
    end_date = models.DateField(verbose_name=_("End day"))

    class Meta:
        verbose_name = _("Special period")
        verbose_name_plural = _("Special periods")
        indexes = [
            models.Index(fields=["start_date", "end_date"]),
        ]

    class PERIODTYPE(models.TextChoices):
        PUBLICHOLIDAYS = "public holidays", _("public holidays")
        SCHOOLVACATIONS = "school vacations", _("school vacations")

    periodtype = models.CharField(
        _("Period type"),
        max_length=20,
        choices=PERIODTYPE.choices,
        default=PERIODTYPE.PUBLICHOLIDAYS,
    )

    def clean(self):
        # Call the parent class's clean() method
        super().clean()

        # Check that the end date is after or equal to the start date
        if self.end_date < self.start_date:
            raise ValidationError(
                {
                    "end_date": _(
                        "The end date must be after or equal to the start date."
                    )
                }
            )

    def __str__(self):
        n = self.periodtype + ' "' + self.name + '"'
        if self.start_date == self.end_date:
            return n + _(" on ") + str(self.start_date)
        else:
            return (
                n + _(" from ") + str(self.start_date) + _(" to ") + str(self.end_date)
            )

    def load_from_ical(uploaded_file, periodtype):
        # load file
        try:
            file_content = uploaded_file.read()
            calendar = icalendar.Calendar.from_ical(file_content)

            nb_error = 0
            nb_overlap = 0
            periods = []
            periods_to_create = []

            # extract events
            for event in calendar.walk("VEVENT"):
                try:
                    name = event.decoded("SUMMARY").decode()
                    r = event.decoded("DTSTART")
                    if isinstance(r, datetime):
                        start_date = r.date()
                    elif isinstance(r, date):
                        start_date = r
                    r = event.decoded("DTEND")
                    if isinstance(r, datetime):
                        end_date = r.date()
                    elif isinstance(r, date):
                        end_date = r
                    periods.append(
                        SpecialPeriod(
                            name=name,
                            periodtype=periodtype,
                            start_date=start_date,
                            end_date=end_date,
                        )
                    )
                except Exception:
                    nb_error += 1

            for p in periods:
                overlap_exists = SpecialPeriod.objects.filter(
                    Q(periodtype=p.periodtype)
                    & Q(start_date__lte=p.end_date)
                    & Q(end_date__gte=p.start_date)
                ).exists()

                if overlap_exists:
                    nb_overlap += 1
                else:
                    periods_to_create.append(p)

            SpecialPeriod.objects.bulk_create(periods_to_create)
            return len(periods_to_create), nb_overlap, nb_error, None
        except Exception as e:
            return 0, 0, 0, str(e)
