# project/server/models.py

import jwt
import datetime

from project.server import app, db, bcrypt

class User(db.Model):
    """ User Model for storing user related details """
    __tablename__ = "users"

    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    username = db.Column(db.String(255), unique=True, nullable=False)
    email = db.Column(db.String(255), unique=True, nullable=False)
    password = db.Column(db.String(255), nullable=False)
    name = db.Column(db.String(255), nullable=False)
    age = db.Column(db.Integer, nullable=False)
    address = db.Column(db.Integer(255), nullable=False)
    registered_on = db.Column(db.DateTime, nullable=False)
    admin = db.Column(db.Boolean, nullable=False, default=False)

    def __init__(self, email, username, password, name, age, address, admin=False):
        self.email = email
        self.username = username
        self.password = bcrypt.generate_password_hash(
            password, app.config.get('BCRYPT_LOG_ROUNDS')
        ).decode()
        self.name = name
        self.age = age
        self.address = address
        self.registered_on = datetime.datetime.now()
        self.admin = admin

    def encode_auth_token(self, user_id):
        """
        Generates the Auth Token
        :return: string
        """
        try:
            payload = {
                'exp': datetime.datetime.utcnow() + datetime.timedelta(days=0, seconds=5),
                'iat': datetime.datetime.utcnow(),
                'sub': user_id
            }
            return jwt.encode(
                payload,
                app.config.get('SECRET_KEY'),
                algorithm='HS256'
            )
        except Exception as e:
            return e

    @staticmethod
    def decode_auth_token(auth_token):
        """
        Validates the auth token
        :param auth_token:
        :return: integer|string
        """
        try:
            payload = jwt.decode(auth_token, app.config.get('SECRET_KEY'))
            is_blacklisted_token = BlacklistToken.check_blacklist(auth_token)
            if is_blacklisted_token:
                return 'Token blacklisted. Please log in again.'
            else:
                return payload['sub']
        except jwt.ExpiredSignatureError:
            return 'Signature expired. Please log in again.'
        except jwt.InvalidTokenError:
            return 'Invalid token. Please log in again.'


class BlacklistToken(db.Model):
    """
    Token Model for storing JWT tokens
    """
    __tablename__ = 'blacklist_tokens'

    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    token = db.Column(db.String(500), unique=True, nullable=False)
    blacklisted_on = db.Column(db.DateTime, nullable=False)

    def __init__(self, token):
        self.token = token
        self.blacklisted_on = datetime.datetime.now()

    def __repr__(self):
        return '<id: token: {}'.format(self.token)

    @staticmethod
    def check_blacklist(auth_token):
        # Check whether auth token has been blacklisted
        res = BlacklistToken.query.filter_by(token=str(auth_token)).first()
        if res:
            return True
        else:
            return False

[(12, 'project.server.db.Column', 'db.Column', False, 'from project.server import app, db, bcrypt\n'), (17, 'project.server.db.Column', 'db.Column', False, 'from project.server import app, db, bcrypt\n'), (19, 'project.server.db.Column', 'db.Column', False, 'from project.server import app, db, bcrypt\n'), (20, 'project.server.db.Column', 'db.Column', False, 'from project.server import app, db, bcrypt\n'), (79, 'project.server.db.Column', 'db.Column', False, 'from project.server import app, db, bcrypt\n'), (81, 'project.server.db.Column', 'db.Column', False, 'from project.server import app, db, bcrypt\n'), (13, 'project.server.db.String', 'db.String', False, 'from project.server import app, db, bcrypt\n'), (14, 'project.server.db.String', 'db.String', False, 'from project.server import app, db, bcrypt\n'), (15, 'project.server.db.String', 'db.String', False, 'from project.server import app, db, bcrypt\n'), (16, 'project.server.db.String', 'db.String', False, 'from project.server import app, db, bcrypt\n'), (18, 'project.server.db.Integer', 'db.Integer', False, 'from project.server import app, db, bcrypt\n'), (31, 'datetime.datetime.now', 'datetime.datetime.now', False, 'import datetime\n'), (80, 'project.server.db.String', 'db.String', False, 'from project.server import app, db, bcrypt\n'), (85, 'datetime.datetime.now', 'datetime.datetime.now', False, 'import datetime\n'), (42, 'datetime.datetime.utcnow', 'datetime.datetime.utcnow', False, 'import datetime\n'), (47, 'project.server.app.config.get', 'app.config.get', False, 'from project.server import app, db, bcrypt\n'), (61, 'project.server.app.config.get', 'app.config.get', False, 'from project.server import app, db, bcrypt\n'), (26, 'project.server.app.config.get', 'app.config.get', False, 'from project.server import app, db, bcrypt\n'), (41, 'datetime.datetime.utcnow', 'datetime.datetime.utcnow', False, 'import datetime\n'), (41, 'datetime.timedelta', 'datetime.timedelta', False, 'import datetime\n')]