from flask_login import login_user
from sqlalchemy.orm import backref

from __init__ import *
from datetime import datetime
from flask import session
from exceptions import *
from abc import ABCMeta, abstractmethod


class AbstUser():
    __metaclass__ = ABCMeta

    @abstractmethod
    def login(self, authentication: bool = None, password: str = None):
        if authentication:
            if not check_password_hash(self.password, password):
                raise ValueError('Введённые пароли различаются')
        login_user(self)
        return True

    @abstractmethod
    def register(self):
        pass

    @abstractmethod
    def authentication(self):
        pass

    @staticmethod
    def __check_user_data(login, email):
        if login and email:
            if len(login) < 3 and len(login) < 48:
                raise ValueError('Логин слишком короткий!')
            if len(email) > 40:
                raise ValueError('Логин слишком короткий!')
        return True

    @staticmethod
    def __check_password_equality(password, password2):
        if password == password2:
            return True
        return False

    def __repr__(self):
        return "<{}:{} {}>".format(self.id, self.email, self.login)

class News(db.Model):
    __tablename__ = 'news'

    id = db.Column(db.Integer(), primary_key=True)
    title = db.Column(db.String(48))
    content = db.Column(db.Text())
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
    user = db.relationship("User", backref=backref("users", lazy="dynamic"))
    image = db.Column(db.Text())
    created_at = db.Column(db.DateTime(), default=datetime.utcnow)

    def create(self):
        db.session.add(self)
        db.session.commit()

    def delete(self, user_id: int = None):
        if user_id:
            user = User.query.get(user_id)
            if user.id != self.user_id:
                raise NotEnoughRights
        db.session.delete(self)
        db.session.commit()

    def __repr__(self):
        return "<{}:{} {}>".format(self.id, self.content, self.created_at)


class User(AbstUser, db.Model, UserMixin):
    __tablename__ = 'user'
    __mapper_args__ = {
        'polymorphic_identity': 'user',
    }

    id = db.Column(db.Integer(), primary_key=True)
    email = db.Column(db.String(64), unique=True)
    login = db.Column(db.String(48), unique=True)
    password = db.Column(db.Text())
    created_at = db.Column(db.DateTime(), default=datetime.utcnow)

    def login(self, *args, **kwargs):
        super().login(*args, **kwargs)

    def register(self, email, login, password, password2):

        if self.__check_user_data(login, email):
            if self.__check_password_equality(password, password2):

                try:
                    user = User(email=email, login=login, password=generate_password_hash(password))
                    db.session.add(user)
                    db.session.commit()
                    return user
                except ExistingLogin:
                    raise ValueError('Такой логин уже существует!')
            else:
                raise DataNotMatch('Пароли не совпадают!')
        else:
            raise ValueError('Логин и пароль не могут содержать меньше 4 символов!')

    def authentication(self):
        user = self.query.filter_by(email=self.email, password=self.password).first()
        if user:
            return user
        return None

class Admin(User, db.Model):
    __tablename__ = 'admin'
    __mapper_args__ = {
        'polymorphic_identity': 'admin',
    }

db.create_all()


@manager.user_loader
def load_user(user_id):
    return User.query.get(user_id)
