from datetime import datetime
import uuid

from sqlalchemy import Column, Integer, Boolean, Unicode, DateTime, ForeignKey, UniqueConstraint, Table
from sqlalchemy.orm import relationship

from brewman.models.guidtype import GUID
from brewman.models import Base, DBSession


thread_tag = Table(
    'msg_threadtags', Base.metadata,
    Column('ThreadTagID', GUID(), primary_key=True, default=uuid.uuid4),
    Column('ThreadID', GUID(), ForeignKey('msg_threads.ThreadID'), nullable=False),
    Column('TagID', GUID(), ForeignKey('msg_tags.TagID'), nullable=False),
    UniqueConstraint('ThreadID', 'TagID')
)


class Tag(Base):
    __tablename__ = 'msg_tags'

    id = Column('TagID', GUID(), primary_key=True, default=uuid.uuid4)
    name = Column('Name', Unicode(100), unique=True, nullable=False)
    css_class = Column('CssClass', Unicode(100))

    def __init__(self, name=None, css_class=None):
        self.name = name
        self.css_class = css_class

    @classmethod
    def by_id(cls, id):
        return DBSession.query(cls).filter(cls.id == id).first()

    @classmethod
    def by_name(cls, name):
        return DBSession.query(cls).filter(cls.name == name).first()

    @classmethod
    def list(cls):
        return DBSession.query(cls).all()

    @classmethod
    def query(cls):
        return DBSession.query(cls)


class Thread(Base):
    __tablename__ = 'msg_threads'

    id = Column('ThreadID', GUID(), primary_key=True, default=uuid.uuid4)
    title = Column('Title', Unicode(1000), nullable=False)
    creation_date = Column('CreationDate', DateTime(timezone=True), nullable=False)
    user_id = Column('UserID', GUID(), ForeignKey('auth_users.UserID'), nullable=False)
    priority = Column('Priority', Integer, nullable=False)
    public = Column('Public', Boolean, nullable=False)
    closed = Column('Closed', Boolean, nullable=False)

    posts = relationship('Post', backref='thread', cascade="delete, delete-orphan", cascade_backrefs=False)
    subscribers = relationship('Subscriber', backref='thread', cascade="delete, delete-orphan", cascade_backrefs=False)
    user = relationship('User', primaryjoin="User.id==Thread.user_id", cascade=None)
    tags = relationship("Tag", secondary=thread_tag, backref='threads')

    def __init__(self, title=None, creation_date=None, user_id=None, priority=5, public=False, closed=False):
        self.title = title
        self.creation_date = datetime.utcnow() if creation_date is None else creation_date
        self.user_id = user_id
        self.priority = priority
        self.public = public
        self.closed = closed

    @classmethod
    def by_id(cls, id):
        if not isinstance(id, uuid.UUID):
            id = uuid.UUID(id)
        return DBSession.query(cls).filter(cls.id == id).first()

    @classmethod
    def by_title(cls, title):
        return DBSession.query(cls).filter(cls.title == title).first()

    @classmethod
    def list(cls):
        return DBSession.query(cls).all()

    @classmethod
    def query(cls):
        return DBSession.query(cls)


class Post(Base):
    __tablename__ = 'msg_posts'

    id = Column('PostID', GUID(), primary_key=True, default=uuid.uuid4)
    content = Column('Content', Unicode(1000), nullable=False)
    creation_date = Column('CreationDate', DateTime(timezone=True), nullable=False)
    user_id = Column('UserID', GUID(), ForeignKey('auth_users.UserID'), nullable=False)
    date = Column('Date', DateTime, nullable=False)
    thread_id = Column('ThreadID', GUID(), ForeignKey('msg_threads.ThreadID'), nullable=False)

    user = relationship('User', primaryjoin="User.id==Post.user_id", cascade=None)

    def __init__(self, content='', creation_date=None, user_id=None, date=None):
        self.content = content
        self.creation_date = datetime.utcnow() if creation_date is None else creation_date
        self.user_id = user_id
        self.date = self.creation_date if date is None else date

    @classmethod
    def by_id(cls, id):
        if not isinstance(id, uuid.UUID):
            id = uuid.UUID(id)
        return DBSession.query(cls).filter(cls.id == id).first()

    @classmethod
    def list(cls, thread_id):
        return DBSession.query(cls).filter(cls.thread_id == thread_id).order_by(cls.date).all()

    @classmethod
    def query(cls):
        return DBSession.query(cls)


class Subscriber(Base):
    __tablename__ = 'msg_subscribers'
    __tableagrs__ = (UniqueConstraint('ThreadID', 'UserID'))
    id = Column('SubscriberID', GUID(), primary_key=True, default=uuid.uuid4)
    thread_id = Column('ThreadID', GUID(), ForeignKey('msg_threads.ThreadID'), nullable=False)
    user_id = Column('UserID', GUID(), ForeignKey('auth_users.UserID'), nullable=False)
    read = Column('Read', Boolean, nullable=False)

    user = relationship('User', primaryjoin="User.id==Subscriber.user_id", cascade=None)

    def __init__(self, thread_id=None, user_id=None, read=False):
        self.thread_id = thread_id
        self.user_id = user_id
        self.read = read