import json

__author__ = 'tanshu'

import re
import uuid

import pkg_resources
from pyramid.response import Response, FileResponse
from pyramid.security import authenticated_userid
from pyramid.view import view_config
import transaction

from ... import groupfinder
from ...models import DBSession
from ...models.auth import User, Role
from ...models.validation_exception import TryCatchFunction, ValidationError


class UserView(object):
    def __init__(self, request):
        self.request = request
        self.user = authenticated_userid(request)
        self.permissions = None
        self.has_permission = False
        if self.user is not None:
            self.user = User.by_id(self.user)
            self.has_permission = 'Users' in groupfinder(self.user.id, request)

    @view_config(route_name='user_list', permission='Users')
    @view_config(request_method='GET', route_name='user_id', permission='Authenticated')
    @view_config(request_method='GET', route_name='user', permission='Users')
    def html(self):
        package, resource = 'picard:static/base.html'.split(':', 1)
        icon = pkg_resources.resource_filename(package, resource)
        return FileResponse(icon, request=self.request)


    @view_config(request_method='POST', route_name='api_user', renderer='json', permission='Users')
    def save(self):
        return self.save_user()


    @TryCatchFunction
    def save_user(self):
        user = User(self.request.json_body['Name'], self.request.json_body['Password'],
                    self.request.json_body['LockedOut'])
        DBSession.add(user)
        self.add_roles(user, self.request.json_body['Roles'])
        transaction.commit()
        return self.user_info(user.id)


    @view_config(request_method='POST', route_name='api_user_id', renderer='json', permission='Authenticated')
    def update(self):
        id = self.request.matchdict['id']
        p = re.compile('^[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}$')
        if p.match(id):
            user = User.by_id(uuid.UUID(id))
        else:
            user = User.by_name(id)
        return self.update_user(user)

    @TryCatchFunction
    def update_user(self, user):
        if user is None:
            raise ValidationError('Not Found', 'User name / id not found')
        if self.has_permission:
            user.name = self.request.json_body['Name']
            user.locked_out = self.request.json_body['LockedOut']
            self.add_roles(user, self.request.json_body['Roles'])

        if self.request.json_body['Password'] != '' and self.request.json_body['Password'] != user.password:
            user.password = self.request.json_body['Password']
        transaction.commit()
        return self.user_info(user.id)


    @view_config(request_method='DELETE', route_name='api_user_id', renderer='json', permission='Users')
    def delete(self):
        id = self.request.matchdict['id', None]
        response = Response(json.dumps(('Not Implemented', "User deletion not implemented")))
        response.status_int = 500
        return response


    @view_config(request_method='GET', route_name='api_user_id', renderer='json', permission='Authenticated')
    def show_id(self):
        id = self.request.matchdict['id']
        p = re.compile('^[A-Za-z0-9]{8}-[A-Za-z0-9]{4}-[A-Za-z0-9]{4}-[A-Za-z0-9]{4}-[A-Za-z0-9]{12}$')
        if p.match(id):
            id = uuid.UUID(id)
        return self.user_info(id)


    @view_config(request_method='GET', route_name='api_user', renderer='json', permission='Users')
    def show_blank(self):
        return self.user_info(None)


    @view_config(request_method='GET', route_name='api_user', renderer='json', request_param='list', permission='Users')
    def show_list(self):
        list = User.list()
        users = []
        for item in list:
            user = {'Name': item.name, 'LockedOut': item.locked_out,
                    'Roles': [], 'Url': self.request.route_url('user_id', id=item.name)}
            for role in item.roles:
                user['Roles'].append(role.name)
            users.append(user)
        return users


    @view_config(request_method='GET', route_name='api_user', renderer='json', request_param='names',
                 permission='Authenticated')
    def show_name(self):
        list = User.query().filter(User.locked_out == False).order_by(User.name).all()
        users = [{'Name': item.name} for item in list]
        # for item in list:
        #     users.append({'Name': item.name})
        return users


    def user_info(self, id):
        if id is None:
            account = {'Name': '', 'LockedOut': False, 'Roles': []}
            for item in Role.list():
                account['Roles'].append({'RoleID': item.id, 'Name': item.name, 'Enabled': False})
            return account

        if isinstance(id, uuid.UUID):
            user = User.by_id(id)
        else:
            user = User.by_name(id)

        if self.has_permission:
            account = {'UserID': user.id, 'Name': user.name, 'Password': '', 'LockedOut': user.locked_out, 'Roles': []}
            for item in Role.list():
                account['Roles'].append(
                    {'RoleID': item.id, 'Name': item.name, 'Enabled': True if item in user.roles else False})
        elif self.user.id == user.id:
            account = {'UserID': user.id, 'Name': user.name, 'Password': '', 'LockedOut': user.locked_out, 'Roles': []}
        else:
            response = Response(json.dumps(('Authorization', "User can only update his/her password")))
            response.status_int = 500
            return response
        return account


    def add_roles(self, user, roles):
        for role in roles:
            id = uuid.UUID(role['RoleID'])
            ur = [r for r in user.roles if r.id == id]
            ur = None if len(ur) == 0 else ur[0]
            if role['Enabled'] and ur is None:
                user.roles.append(Role.by_id(id))
            elif not role['Enabled'] and ur:
                user.roles.remove(ur)