from typing import Optional
import datetime

from sqlalchemy import Column, Date, DateTime, Enum, ForeignKeyConstraint, Identity, Integer, PrimaryKeyConstraint, Table, Text
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship

class Base(DeclarativeBase):
    pass


class Affiliation(Base):
    __tablename__ = 'affiliation'
    __table_args__ = (
        PrimaryKeyConstraint('org_name', name='affiliation_pkey'),
    )

    org_name: Mapped[str] = mapped_column(Text, primary_key=True)
    website: Mapped[str] = mapped_column(Text, nullable=False)
    country: Mapped[str] = mapped_column(Text, nullable=False)

    person_affiliation: Mapped[list['PersonAffiliation']] = relationship('PersonAffiliation', back_populates='affiliation')


class Conference(Base):
    __tablename__ = 'conference'
    __table_args__ = (
        PrimaryKeyConstraint('year', name='conference_pkey'),
    )

    year: Mapped[int] = mapped_column(Integer, primary_key=True)
    location: Mapped[str] = mapped_column(Text, nullable=False)

    paper: Mapped[list['Paper']] = relationship('Paper', back_populates='conference')


class Person(Base):
    __tablename__ = 'person'
    __table_args__ = (
        PrimaryKeyConstraint('email', name='person_pkey'),
    )

    email: Mapped[str] = mapped_column(Text, primary_key=True)
    first_name: Mapped[str] = mapped_column(Text, nullable=False)
    last_name: Mapped[str] = mapped_column(Text, nullable=False)

    paper: Mapped[list['Paper']] = relationship('Paper', back_populates='person')
    person_affiliation: Mapped[list['PersonAffiliation']] = relationship('PersonAffiliation', back_populates='person')
    paper_author: Mapped[list['PaperAuthor']] = relationship('PaperAuthor', back_populates='person')


class Topic(Base):
    __tablename__ = 'topic'
    __table_args__ = (
        PrimaryKeyConstraint('topic_id', name='topic_pkey'),
    )

    topic_id: Mapped[int] = mapped_column(Integer, Identity(start=1, increment=1, minvalue=1, maxvalue=2147483647, cycle=False, cache=1), primary_key=True)
    topic_name: Mapped[str] = mapped_column(Text, nullable=False)

    paper: Mapped[list['Paper']] = relationship('Paper', secondary='paper_topic', back_populates='topic')
    reviewer: Mapped[list['Reviewer']] = relationship('Reviewer', secondary='expertise', back_populates='topic')


class Paper(Base):
    __tablename__ = 'paper'
    __table_args__ = (
        ForeignKeyConstraint(['contact_email'], ['person.email'], name='paper_contact_email_fkey'),
        ForeignKeyConstraint(['year'], ['conference.year'], name='paper_year_fkey'),
        PrimaryKeyConstraint('paper_id', name='paper_pkey')
    )

    paper_id: Mapped[int] = mapped_column(Integer, Identity(start=1, increment=1, minvalue=1, maxvalue=2147483647, cycle=False, cache=1), primary_key=True)
    title: Mapped[str] = mapped_column(Text, nullable=False)
    abstract: Mapped[str] = mapped_column(Text, nullable=False)
    filename: Mapped[str] = mapped_column(Text, nullable=False)
    contact_email: Mapped[str] = mapped_column(Text, nullable=False)
    year: Mapped[int] = mapped_column(Integer, nullable=False)

    person: Mapped['Person'] = relationship('Person', back_populates='paper')
    conference: Mapped['Conference'] = relationship('Conference', back_populates='paper')
    topic: Mapped[list['Topic']] = relationship('Topic', secondary='paper_topic', back_populates='paper')
    history: Mapped[list['History']] = relationship('History', back_populates='paper')
    paper_author: Mapped[list['PaperAuthor']] = relationship('PaperAuthor', back_populates='paper')
    review: Mapped[list['Review']] = relationship('Review', back_populates='paper')


class PersonAffiliation(Base):
    __tablename__ = 'person_affiliation'
    __table_args__ = (
        ForeignKeyConstraint(['email'], ['person.email'], name='person_affiliation_email_fkey'),
        ForeignKeyConstraint(['org_name'], ['affiliation.org_name'], name='person_affiliation_org_name_fkey'),
        PrimaryKeyConstraint('email', 'org_name', name='person_affiliation_pkey')
    )

    email: Mapped[str] = mapped_column(Text, primary_key=True)
    org_name: Mapped[str] = mapped_column(Text, primary_key=True)
    from_date: Mapped[Optional[datetime.date]] = mapped_column(Date)
    to_date: Mapped[Optional[datetime.date]] = mapped_column(Date)

    person: Mapped['Person'] = relationship('Person', back_populates='person_affiliation')
    affiliation: Mapped['Affiliation'] = relationship('Affiliation', back_populates='person_affiliation')


class Reviewer(Person):
    __tablename__ = 'reviewer'
    __table_args__ = (
        ForeignKeyConstraint(['email'], ['person.email'], name='reviewer_email_fkey'),
        PrimaryKeyConstraint('email', name='reviewer_pkey')
    )

    email: Mapped[str] = mapped_column(Text, primary_key=True)
    phone: Mapped[Optional[str]] = mapped_column(Text)

    topic: Mapped[list['Topic']] = relationship('Topic', secondary='expertise', back_populates='reviewer')
    review: Mapped[list['Review']] = relationship('Review', back_populates='reviewer')


t_expertise = Table(
    'expertise', Base.metadata,
    Column('email', Text, primary_key=True),
    Column('topic_id', Integer, primary_key=True),
    ForeignKeyConstraint(['email'], ['reviewer.email'], name='expertise_email_fkey'),
    ForeignKeyConstraint(['topic_id'], ['topic.topic_id'], name='expertise_topic_id_fkey'),
    PrimaryKeyConstraint('email', 'topic_id', name='expertise_pkey')
)


class History(Base):
    __tablename__ = 'history'
    __table_args__ = (
        ForeignKeyConstraint(['paper_id'], ['paper.paper_id'], name='history_paper_id_fkey'),
        PrimaryKeyConstraint('paper_id', 'timestamp', name='history_pkey')
    )

    paper_id: Mapped[int] = mapped_column(Integer, primary_key=True)
    timestamp: Mapped[datetime.datetime] = mapped_column(DateTime, primary_key=True)
    paper_status: Mapped[str] = mapped_column(Enum('SUBMITTED', 'UNDER_REVIEW', 'REVISION', 'RESUBMITTED', 'REJECTED', 'ACCEPTED', 'PUBLISHED', name='status'), nullable=False)
    notes: Mapped[Optional[str]] = mapped_column(Text)

    paper: Mapped['Paper'] = relationship('Paper', back_populates='history')


class PaperAuthor(Base):
    __tablename__ = 'paper_author'
    __table_args__ = (
        ForeignKeyConstraint(['email'], ['person.email'], name='paper_author_email_fkey'),
        ForeignKeyConstraint(['paper_id'], ['paper.paper_id'], name='paper_author_paper_id_fkey'),
        PrimaryKeyConstraint('paper_id', 'email', name='paper_author_pkey')
    )

    paper_id: Mapped[int] = mapped_column(Integer, primary_key=True)
    email: Mapped[str] = mapped_column(Text, primary_key=True)
    rank: Mapped[int] = mapped_column(Integer, nullable=False, comment='author order')

    person: Mapped['Person'] = relationship('Person', back_populates='paper_author')
    paper: Mapped['Paper'] = relationship('Paper', back_populates='paper_author')


t_paper_topic = Table(
    'paper_topic', Base.metadata,
    Column('paper_id', Integer, primary_key=True),
    Column('topic_id', Integer, primary_key=True),
    ForeignKeyConstraint(['paper_id'], ['paper.paper_id'], name='paper_topic_paper_id_fkey'),
    ForeignKeyConstraint(['topic_id'], ['topic.topic_id'], name='paper_topic_topic_id_fkey'),
    PrimaryKeyConstraint('paper_id', 'topic_id', name='paper_topic_pkey')
)


class Review(Base):
    __tablename__ = 'review'
    __table_args__ = (
        ForeignKeyConstraint(['email'], ['reviewer.email'], name='review_email_fkey'),
        ForeignKeyConstraint(['paper_id'], ['paper.paper_id'], name='review_paper_id_fkey'),
        PrimaryKeyConstraint('paper_id', 'email', name='review_pkey'),
        {'comment': 'Scores range from 1 to 5'}
    )

    paper_id: Mapped[int] = mapped_column(Integer, primary_key=True)
    email: Mapped[str] = mapped_column(Text, primary_key=True)
    merit: Mapped[int] = mapped_column(Integer, nullable=False)
    relevance: Mapped[int] = mapped_column(Integer, nullable=False)
    readability: Mapped[int] = mapped_column(Integer, nullable=False)
    originality: Mapped[int] = mapped_column(Integer, nullable=False)
    author_comments: Mapped[str] = mapped_column(Text, nullable=False)
    committee_comments: Mapped[Optional[str]] = mapped_column(Text)

    reviewer: Mapped['Reviewer'] = relationship('Reviewer', back_populates='review')
    paper: Mapped['Paper'] = relationship('Paper', back_populates='review')
