import os
from flask_sqlalchemy import SQLAlchemy
import utils
import flask
import random
from datetime import datetime
from werkzeug.security import check_password_hash, generate_password_hash
import networkrules as nwr

db = SQLAlchemy()

connexions = db.Table('connexions',
    db.Column('user_id', db.Integer, db.ForeignKey('user.id')),
    db.Column('asked_id', db.Integer, db.ForeignKey('user.id'))
)


class User(db.Model):
    id = db.Column(db.Integer, primary_key = True)
    username = db.Column(db.String(32), unique=True, nullable=False)
    password = db.Column(db.String(64), nullable=False)
    profile_pic_fn = db.Column(db.String(64), nullable=False)
    # email = db.Column(db.String(64), nullable=False)
    score = db.Column(db.Integer, default=nwr.M_new)
    subscription_date = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
    #
    posts = db.relationship("Post", backref="user") #posted by the user
    comments = db.relationship("Comment", backref="user") #posted by the user
    answers = db.relationship("AnswerToComment", backref="user") #posted by the user
    connexions = db.relationship("User",
        secondary = connexions, #xxx backref="asked_by",
        primaryjoin = (connexions.c.user_id == id), 
        secondaryjoin = (connexions.c.asked_id == id),
        lazy = 'dynamic'
    ) 


    @classmethod
    def check_up(cls, username, password, profile_pic_fn="", ignore_pic=False):
        """Check if Username or Password is empty"""
        if not username:
            return 'username is required.'
        elif not password:
            return 'password is required.'
        elif not profile_pic_fn and not ignore_pic:
            return 'profile pic is required.'
        return None

    @classmethod
    def register(cls, username, password, profile_pic_fn, commit=True):
        error = cls.check_up(username, password, profile_pic_fn)
        if error is None:
            try:
                password = generate_password_hash(password)
                u = User(username=username, password=password,
                        profile_pic_fn=profile_pic_fn, score=1000)
                print("Adding user", u)
                db.session.add(u)
                if commit:
                    db.session.commit()
            except Exception as e:
                print("Failed to register user")
                print("Error:", e)
                db.session.rollback()
                user = User.query.filter_by(username=username).first()
                if user:
                    error = "this username is already taken"
        return error

    @classmethod
    def try_login(cls, username, password):
        error = cls.check_up(username, password, ignore_pic=True)
        if error is None:
            user = User.query.filter_by(username=username).first()
            if user is None:
                return 'Incorrect username.', None
            elif not check_password_hash(user.password, password):
                return 'Incorrect password.', None
            return None, user
        return error, None

    def __repr__(self):
        return "<User: {}>".format(self.username)

    def add_connexion(self, other, commit=True):
        self_id = str(self.id)
        other_id = str(other.id)
        if self_id == other_id:
            return "You cannot connect to yourself"
        else:
            self.connexions.append(other)
            db.session.flush()
            other.connexions.append(self)
            # db.session.flush() #I do not know if I need this one
            if commit:
                db.session.commit()
            return "Successfully connected to " + other.username


    def get_profile_pic_filename(self):
        url = flask.url_for('static', filename = os.path.join("images/",self.profile_pic_fn))
        return url


RAND_USERNAMES = ["Pierre", "Paul", "Jacques", "Moh", "Jacob", "Li", "Jean", "Ali", "Bob", "Alice",
                    "Boubakar", "Gregor", "Eudes", "Marcel", "Plutarque", "Platon", "Socrate",
                    "Aristote", "Yann", "Koraly", "Kevin", "Patate", "Banane", "Solal"]
def fake_registers(n):
    done = []
    username = "Jean Le Bon"
    for i in range(n):
        while username in done:
            username = random.choice(RAND_USERNAMES) + "_" + str(random.randint(0,1e2-1)).zfill(2)
        done.append(username)
        password = "lol"
        from fake import RAND_IMGS
        img_fn = random.choice(RAND_IMGS)
        print("Creation aleatoire de", username, "--->", i)
        error = User.register(username, password, img_fn, commit=False)
        if error:
            print("ERROR", error)
    db.session.commit()


def fake_links_elo(n):
    all_users = User.query.all()
    print("****TOUS", len(all_users))
    for i in range(n):
        print(i)
        u1 = random.choice(all_users)
        u2 = random.choice(all_users)
        if u1 is u2:
            print("same")
        elif u1 in u2.connexions: #Si les agents sont deja potes...
            nwr.update(u1, u2)
            print("update", u1, u2)
        elif nwr.match(u1, u2): #sinon, si l'un d'eux veut être pote avec l'autre...
            error = u1.add_connexion(u2, commit=False)
            print(error)
        else: #then the big fish doesnt want to become friend
            pass
            # print("Match echoue", u1, u2)
        renormalize_scores(commit=False)
        db.session.commit()

def renormalize_scores(commit=False):
    all_users = User.query.all()
    M = max([u.score for u in all_users])
    for u in all_users:
        u.score /= M
        u.score *= nwr.M0
    if commit:
        db.session.commit()

