__author__ = 'tanshu'

import uuid
from hashlib import md5

from sqlalchemy.schema import ForeignKey, Table
from sqlalchemy import Column, Boolean, Unicode
from sqlalchemy.orm import synonym, relationship

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


def encrypt(val):
    return md5(val.encode('utf-8') + "Salt".encode('utf-8')).hexdigest()


user_role = Table(
    'auth_user_roles', Base.metadata,
    Column('user_role_id', GUID(), primary_key=True, default=uuid.uuid4),
    Column('user_id', GUID(), ForeignKey('auth_users.user_id')),
    Column('role_id', GUID(), ForeignKey('auth_roles.role_id'))
)

role_group = Table(
    'auth_permission_roles', Base.metadata,
    Column('permission_role_id', GUID(), primary_key=True, default=uuid.uuid4),
    Column('permission_id', GUID(), ForeignKey('auth_permissions.permission_id')),
    Column('role_id', GUID(), ForeignKey('auth_roles.role_id'))
)


class User(Base):
    __tablename__ = 'auth_users'

    id = Column('user_id', GUID(), primary_key=True, default=uuid.uuid4)
    name = Column('name', Unicode(255), unique=True)
    _password = Column('password', Unicode(60))
    locked_out = Column('locked_out', Boolean)

    roles = relationship('Role', secondary=user_role)

    def _get_password(self):
        return self._password

    def _set_password(self, password):
        self._password = encrypt(password)

    password = property(_get_password, _set_password)
    password = synonym('_password', descriptor=password)


    @property
    def __name__(self):
        return self.name

    def __init__(self, name=None, password=None, locked_out=None, id=None):
        self.name = name
        self.password = password
        self.locked_out = locked_out
        self.id = id

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

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

    @classmethod
    def auth(cls, name, password):
        user = cls.by_name(name)
        if not user:
            return False, None
        if user.password != encrypt(password) or user.locked_out:
            return False, None
        else:
            return True, user

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

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

    @classmethod
    def filtered_list(cls, name):
        query = DBSession.query(cls)
        for item in name.split():
            query = query.filter(cls.name.ilike('%' + item + '%'))
        return query.order_by(cls.name)


class Role(Base):
    __tablename__ = 'auth_roles'

    id = Column('role_id', GUID(), primary_key=True, default=uuid.uuid4)
    name = Column('name', Unicode(255), unique=True)

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

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

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


class Permission(Base):
    __tablename__ = 'auth_permissions'

    id = Column('permission_id', GUID(), primary_key=True, default=uuid.uuid4)
    name = Column('name', Unicode(255), unique=True)

    groups = relationship('Role', secondary=role_group, backref='permissions')

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

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

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

