from flask_login import UserMixin
from sqlalchemy.orm import backref, load_only, relationship
from sqlalchemy.sql.elements import and_, or_
from overflow import login_manager
from overflow import db
from werkzeug.security import generate_password_hash, check_password_hash
import datetime


class Utilisateur(UserMixin, db.Model):

    __tablename__ = 'utilisateur'
    matricule = db.Column(db.String(80), primary_key=True)
    prenom = db.Column(db.String(80), nullable=False)
    nom = db.Column(db.String(80), nullable=False)
    anniversaire = db.Column(db.Date, nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)
    password_hash = db.Column(db.String(128))
    # Comment on gère le fait qu'un user est modo ? (lors de création de compte/register)
    est_modo = db.Column(db.Boolean, default=False)

    def get_id(self):
        return self.matricule

    def set_password(self, password):
        self.password_hash = generate_password_hash(password)

    def check_password(self, password):
        return check_password_hash(self.password_hash, password)

    def get_conversations(self):
        request = db.session.query(Message).filter(
            or_(Message.destinataire == self.matricule,
                Message.destinateur == self.matricule)).options(
                    load_only("destinataire", "destinateur")).all()
        out = set()
        for msg in request:
            out.add(msg.destinateur if msg.destinataire ==
                    self.matricule else msg.destinataire)

        return [Utilisateur.query.get(usr) for usr in out]

    def get_conversation(self, user, after):
        request = db.session.query(Message).filter(
            and_(
                or_(and_(Message.destinataire == self.matricule, Message.destinateur == user),
                    and_(Message.destinateur == self.matricule, Message.destinataire == user)),
                Message.id > after)
        ).all()
        return request


class Post(db.Model):

    __tablename__ = 'post'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    auteur = db.Column(db.String(80), db.ForeignKey('utilisateur.matricule'))
    matiere = db.Column(db.String(256), db.ForeignKey('matiere.matricule'))
    titre = db.Column(db.String(256), unique=True, nullable=False)
    contenu = db.Column(db.String(512), nullable=False)
    date = db.Column(db.Date, nullable=False)
    date_modif = db.Column(db.Date)

    auteur_rel = relationship('Utilisateur', foreign_keys=[
                              auteur], backref="posts")

    matiere_rel = relationship(
        "Matiere", backref="posts", foreign_keys=[matiere])


class Matiere(db.Model):
    __tablename__ = 'matiere'
    matricule = db.Column(db.String(256), primary_key=True)
    titre = db.Column(db.String(128), nullable=False)
    faculte = db.Column(db.String(128), db.ForeignKey('faculte.nom'))
    faculte_rel = relationship("Faculte", foreign_keys=[
                               faculte], backref="cours")


class Faculte(db.Model):
    __tablename__ = 'faculte'
    nom = db.Column(db.String(128), primary_key=True)


class Reponse(db.Model):
    __tablename__ = 'reponse'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    post_id = db.Column(db.Integer, db.ForeignKey('post.id'))
    auteur = db.Column(db.String(80), db.ForeignKey('utilisateur.matricule'))
    contenu = db.Column(db.String(512), nullable=False)
    like_auteur = db.Column(db.Boolean, default=False)
    date = db.Column(db.Date, nullable=False)
    date_modif = db.Column(db.Date)

    post_rel = relationship("Post", backref="reponses",
                            foreign_keys=[post_id])
    utilisateur_rel = relationship(
        "Utilisateur", backref="reponses", foreign_keys=[auteur])


class Like(db.Model):
    __tablename__ = 'like'
    reponse_id = db.Column(db.Integer, db.ForeignKey(
        'reponse.id'), primary_key=True)
    auteur_id = db.Column(db.Integer, db.ForeignKey(
        'utilisateur.matricule'), primary_key=True)

    reponse_rel = relationship("Reponse", foreign_keys=[
                               reponse_id], backref=backref("likes",  cascade="all, delete"))
    auteur_rel = relationship("Utilisateur", foreign_keys=[auteur_id])

    def dict(self):
        return {"rid": self.reponse_id, "aid": self.auteur_id}


class Message(db.Model):

    __tablename__ = 'message'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)

    destinateur = db.Column(
        db.String(80), db.ForeignKey('utilisateur.matricule'))

    destinataire = db.Column(
        db.String(80), db.ForeignKey('utilisateur.matricule'))

    contenu = db.Column(db.String(512), nullable=False)

    date = db.Column(db.DateTime, nullable=False)

    destinataire_rel = relationship("Utilisateur", foreign_keys=[
                                    destinataire], backref="messages_recus")
    destinateur_rel = relationship("Utilisateur", foreign_keys=[
                                   destinateur], backref="messages_envoyes")


db.drop_all()  # would be removed in a production env
db.create_all()

user0 = Utilisateur(
    matricule="jdoe",
    prenom="John",
    nom="Doe",
    anniversaire=datetime.datetime.now(),
    email="john.doe@student.unamur.be",
    est_modo=True
)
user0.set_password('mdptest')

user1 = Utilisateur(
    matricule="jdoe1",
    prenom="John",
    nom="Doe1",
    anniversaire=datetime.datetime.now(),
    email="john.doe1@student.unamur.be",
)
user1.set_password('test')

fac1 = Faculte(nom="Faculté d'informatique")
fac2 = Faculte(nom="Faculté d'économie")

matiere1 = Matiere(matricule="INFOB132",
                   titre="Projet de programmation", faculte=fac1.nom)
matiere2 = Matiere(matricule="INFOB133",
                   titre="Systèmes d'information : étude de cas", faculte=fac1.nom)
matiere3 = Matiere(matricule="ECGEB140", titre="Sociologie", faculte=fac2.nom)
matiere4 = Matiere(matricule="ECGEB120", titre="Philosophie", faculte=fac2.nom)

post1 = Post(auteur=user1.matricule,
             matiere=matiere1.matricule,
             titre="Syntax error: invalid syntax",
             contenu="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque eget nisi eleifend, tristique nisi et, dapibus metus. Quisque elementum velit eget vehicula tincidunt. Duis ultricies augue vitae nisi fringilla, eget ullamcorper risus congue. ",
             date=datetime.datetime.now())

post3 = Post(auteur=user1.matricule,
             matiere=matiere1.matricule,
             titre="Comment faire un cls en python ?",
             contenu="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque eget nisi eleifend, tristique nisi et, dapibus metus. Quisque elementum velit eget vehicula tincidunt. Duis ultricies augue vitae nisi fringilla, eget ullamcorper risus congue. ",
             date=datetime.datetime.now())

post2 = Post(auteur=user0.matricule,
             matiere=matiere2.matricule,
             titre="Qu'est-ce qu'une API ?",
             contenu="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque eget nisi eleifend, tristique nisi et, dapibus metus. Quisque elementum velit eget vehicula tincidunt. Duis ultricies augue vitae nisi fringilla, eget ullamcorper risus congue.",
             date=datetime.datetime.now())


for entity in [user0, user1, matiere1, matiere2, matiere3, matiere4, post1, post2, post3, fac1, fac2,
               Message(destinateur=user0.matricule, destinataire=user1.matricule,
                       contenu="Salut ! Comment ça va ?", date=datetime.datetime.now()),
               Message(destinateur=user1.matricule, destinataire=user0.matricule,
                       contenu="Bien et toi ? ", date=datetime.datetime.now())]:
    db.session.add(entity)


db.session.commit()

reponse1 = Reponse(auteur=user0.matricule,
                   contenu="Lorem ipsum dolor sit amet",
                   date=datetime.datetime.now(),
                   post_id=post1.id)

reponse2 = Reponse(auteur=user1.matricule,
                   contenu="Lorem ipsum dolor sit amet",
                   date=datetime.datetime.now(),
                   post_id=post2.id, like_auteur=True)


reponse3 = Reponse(auteur=user1.matricule,
                   contenu="Lorem ipsum dolor sit amet",
                   date=datetime.datetime.now(),
                   post_id=post2.id, like_auteur=False)


reponse4 = Reponse(auteur=user1.matricule,
                   contenu="Lorem ipsum dolor sit amet",
                   date=datetime.datetime.now(),
                   post_id=post1.id, like_auteur=False)

db.session.add(reponse1)
db.session.add(reponse2)
db.session.add(reponse3)
db.session.commit()

like = Like(reponse_id=reponse1.id, auteur_id=user0.matricule)
like2 = Like(reponse_id=reponse2.id, auteur_id=user0.matricule)

db.session.add(like)
db.session.add(like2)

db.session.commit()


@ login_manager.user_loader
def load_user(matricule):
    return Utilisateur.query.get(matricule)
