"""Database models."""

import sqlalchemy
import sqlalchemy.orm.decl_api
from sqlalchemy import func
from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.orderinglist import ordering_list
from sqlalchemy.orm import relationship
from sqlalchemy.schema import Column, ForeignKey
from sqlalchemy.types import Date, DateTime, Integer, String

from .database import session

Base: sqlalchemy.orm.decl_api.DeclarativeMeta = declarative_base()
Base.query = session.query_property()


class TimeStampedModel(Base):
    """Time stamped model."""

    __abstract__ = True
    created = Column(DateTime, default=func.now())
    modified = Column(DateTime, default=func.now(), onupdate=func.now())


class Conference(TimeStampedModel):
    """Conference."""

    __tablename__ = "conference"
    id = Column(Integer, primary_key=True)
    title = Column(String, nullable=False)
    start = Column(Date)
    end = Column(Date)
    days = Column(Integer)
    timezone = Column(String)
    location = Column(String)
    country = Column(String)
    acronym = Column(String)
    url = Column(String)
    schedule_xml_url = Column(String)


class Event(TimeStampedModel):
    """Event."""

    __tablename__ = "event"
    id = Column(Integer, primary_key=True)
    conference_id = Column(Integer, ForeignKey("conference.id"), nullable=False)
    event_date = Column(DateTime)
    day = Column(Integer)
    guid = Column(String)
    start = Column(String)
    duration = Column(String)
    room = Column(String)
    track = Column(String)
    slug = Column(String)
    title = Column(String, nullable=False)
    description = Column(String)
    event_type = Column(String)
    url = Column(String)

    conference = relationship("Conference", backref="events")

    people_association = relationship(
        "EventPerson",
        order_by="EventPerson.position",
        back_populates="event",
        collection_class=ordering_list("position"),
    )
    people = association_proxy(
        "people_association",
        "person",
        creator=lambda person: EventPerson(person=person),
    )


class Person(TimeStampedModel):
    """Person."""

    __tablename__ = "person"
    id = Column(Integer, primary_key=True)
    name = Column(String)
    wikidata_qid = Column(String)
    gender = Column(String)

    events_association = relationship("EventPerson", back_populates="person")
    events = association_proxy("event_association", "event")


class EventPerson(Base):
    """Event person."""

    __tablename__ = "event_person"
    event_id = Column(Integer, ForeignKey("event.id"), primary_key=True)
    person_id = Column(Integer, ForeignKey("person.id"), primary_key=True)
    position = Column(Integer, nullable=False)
    named_as = Column(String)

    person = relationship("Person", back_populates="events_association")
    event = relationship("Event", back_populates="people_association")