"""
Security related functions including user credential authentication and JWT
based authentication integration.

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

import collections
import logging

import flask
from werkzeug import security

from rookeries import database, errors
from rookeries.users import models
from rookeries.vendors import flask_jwt

Credentials = collections.namedtuple('Credentials', ['username', 'password'])
ADMIN_USERNAME = 'ADMIN_USERNAME'
ADMIN_PASSWORD = 'ADMIN_PASSWORD'
DEFAULT_JWT_SECRET_KEY = 'problematic_penguins'

jwt = flask_jwt.JWT()
logger = logging.getLogger(__name__)


@jwt.authentication_handler
def valid_admin_user_credentials(username, password):
    """Checks if the supplied password matches the stored password hash."""
    # TODO: Attach DB to Flask app context.
    db = database.CouchDB.configure_from_env()
    try:
        user = models.User.find_in_db(db, {'username': username})
        if not security.check_password_hash(user.password, password):
            raise errors.InvalidCredentialsError(username)
        identifier = user.to_api_json()
        # TODO: Make the identifier the username...
        identifier['id'] = user.username
        return identifier

    except database.NoMatchingDocumentFoundError:
        raise errors.InvalidCredentialsError(username)


@jwt.identity_handler
def load_user(payload):
    # TODO: Really rework this or better yet just use PyJWT directly.
    db = database.CouchDB.configure_from_env()
    user = models.User.find_in_db(db, {'username': payload['identity']})
    # TODO: Figure out what happens if no users are found.
    return user.to_api_json()


@jwt.auth_response_handler
def jwt_token_response(access_token, identity):
    response = {
        'access_token': access_token.decode(encoding="utf-8"),
        # TODO: Inject user info into the token, to decode on the frontend.
        'user': identity
    }
    return flask.jsonify(response)
