from dateutil.relativedelta import relativedelta
from sqlalchemy import Boolean, Column, Integer, UnicodeText
from sqlalchemy.event import listens_for

from project import db
from project.models.functions import sanitize_allday_instance
from project.utils import make_check_violation


class EventDate(db.Model):
    __tablename__ = "eventdate"
    id = Column(Integer(), primary_key=True)
    event_id = db.Column(db.Integer, db.ForeignKey("event.id"), nullable=False)
    start = db.Column(db.DateTime(timezone=True), nullable=False, index=True)
    end = db.Column(db.DateTime(timezone=True), nullable=True, index=True)
    allday = db.Column(
        Boolean(),
        nullable=False,
        default=False,
        server_default="0",
    )


@listens_for(EventDate, "before_insert")
@listens_for(EventDate, "before_update")
def purge_event_date(mapper, connect, self):
    sanitize_allday_instance(self)


class EventDateDefinition(db.Model):
    __tablename__ = "eventdatedefinition"
    id = Column(Integer(), primary_key=True)
    event_id = db.Column(db.Integer, db.ForeignKey("event.id"), nullable=False)
    start = db.Column(db.DateTime(timezone=True), nullable=False)
    end = db.Column(db.DateTime(timezone=True), nullable=True)
    allday = db.Column(
        Boolean(),
        nullable=False,
        default=False,
        server_default="0",
    )
    recurrence_rule = Column(UnicodeText())

    def validate(self):
        if self.start and self.end:
            if self.start > self.end:
                raise make_check_violation("The start must be before the end.")

            max_end = self.start + relativedelta(days=14)
            if self.end > max_end:
                raise make_check_violation("An event can last a maximum of 14 days.")


@listens_for(EventDateDefinition, "before_insert")
@listens_for(EventDateDefinition, "before_update")
def before_saving_event_date_definition(mapper, connect, self):
    self.validate()
    sanitize_allday_instance(self)
