"""
Views for managing users.

:copyright: Copyright 2013-2017, Dorian Pula <dorian.pula@amber-penguin-software.ca>
:license: AGPL v3+
"""

import http
import logging

import flask
import jsonschema

from rookeries import database, errors
from rookeries.main import rookeries_app
from rookeries.users import models, schema
from rookeries.vendors import flask_jwt

logger = logging.getLogger(__name__)


def replace_id_with_self_link(user_json):
    del user_json['id']
    user_json['urls'] = {
        'self': flask.url_for('rookeries_app.get_user', username=user_json['username'], _external=True),
    }
    return user_json


@rookeries_app.route('/api/users/<username>', methods=['GET'])
@flask_jwt.jwt_required()
def get_user(username):

    # TODO: Attach DB to Flask app context.
    db = database.CouchDB.configure_from_env()
    found_user = db.find_first_document({
        'type': models.User.doc_type(),
        'username': username,
    })

    if not found_user:
        flask.abort(http.HTTPStatus.NOT_FOUND)

    user = models.User(**found_user)
    return flask.jsonify(user.to_api_json())


@rookeries_app.route('/api/users/', methods=['POST'])
@flask_jwt.jwt_required()
def create_user():
    # Check if request is JSON, and respects the JSON schema
    if not flask.request.is_json:
        flask.abort(http.HTTPStatus.BAD_REQUEST)

    incoming_request = flask.request.get_json()
    jsonschema.validate(incoming_request, schema.USER_CREATION_MODIFICATION_SCHEMA)

    # Creates a user from the json if no user exists with the given username.
    if models.User.query.filter_by(username=incoming_request['username']).first():
        raise errors.ConflictingResourceError('Existing resource already found.  PUT to the resource to update it.')

    user = models.User.from_json(incoming_request)

    user_response = replace_id_with_self_link(user.to_json())
    return flask.jsonify(user_response), http.HTTPStatus.CREATED


@rookeries_app.route('/api/users/<username>', methods=['PUT'])
@flask_jwt.jwt_required()
def update_user(username):
    # Check if request is JSON, and respects the JSON schema
    if not flask.request.is_json:
        flask.abort(http.HTTPStatus.BAD_REQUEST)

    incoming_request = flask.request.get_json()
    jsonschema.validate(incoming_request, schema.USER_CREATION_MODIFICATION_SCHEMA)

    # Check if user allowed to create a user.
    current_user = flask_jwt.current_identity

    if current_user['username'] != username:
        flask.abort(http.HTTPStatus.UNAUTHORIZED)

    # Modifies a user from the json.
    existing_user = models.User.query.filter_by(username=username).first_or_404()
    updated_user = models.User.from_json(incoming_request)
    existing_user.role = updated_user.role
    existing_user.profile.full_name = updated_user.profile.full_name
    existing_user.profile.alias_name = updated_user.profile.alias_name
    existing_user.profile.email = updated_user.profile.email

    user_response = replace_id_with_self_link(updated_user.to_json())
    return flask.jsonify(user_response), http.HTTPStatus.CREATED


# TODO: Add in a patch to update the password of a user.


@rookeries_app.route('/api/users/<username>', methods=['DELETE'])
@flask_jwt.jwt_required()
def delete_user(username):
    user = models.User.query.filter_by(username=username).first_or_404()
    current_user = flask_jwt.current_identity

    if user.username == current_user['username']:
        raise errors.InvalidOperationError(message='Can not delete your own user.')

    return '', http.HTTPStatus.NO_CONTENT
