"""
Functional tests for the user authentication feature.

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

import collections
import http

import jwt
import pytest
import pytest_bdd as bdd
import requests
from pytest_bdd import parsers

from tests import utils

bdd.scenarios('user_authentication.feature')

Credentials = collections.namedtuple('Credentials', ['username', 'password'])


@pytest.fixture(scope='module')
def valid_user(db):
    test_user, password = utils.generate_test_user(db)
    return Credentials(test_user.username, password)


@bdd.given(parsers.parse('I am a {user_type} user with {login_type} credentials'))
def user_credentials(user_type, login_type, valid_user):
    if not user_type == 'valid':
        return Credentials('invalid_user', 'invalid_password')

    if not login_type == 'valid':
        return Credentials(valid_user.username, 'invalid_password')

    return valid_user


@bdd.given('I post my credentials against the auth endpoint')
def auth_endpoint_response(user_credentials: Credentials, api_base_uri):
    return requests.post(f'{api_base_uri}/auth', json={
        'username': user_credentials.username,
        'password': user_credentials.password,
    })


@bdd.then('I get a valid JWT')
def assert_valid_user_json_web_token(user_credentials: Credentials, auth_endpoint_response: requests.Response):
    assert auth_endpoint_response.status_code == http.HTTPStatus.OK

    jwt_token = auth_endpoint_response.json()['access_token']
    assert jwt_token is not None
    decoded_jwt = jwt.decode(jwt_token, verify=False)
    assert 'identity' in decoded_jwt

    assert auth_endpoint_response.json().get('username') == user_credentials.user.username


@bdd.then('I get an unauthorized response')
def assert_unauthorized_response(auth_endpoint_response: requests.Response):
    expected_json = {
        'error': {
            'message': 'Invalid credentials provided.',
            'status_code': http.HTTPStatus.UNAUTHORIZED.value,
        },
    }

    assert auth_endpoint_response.status_code == http.HTTPStatus.UNAUTHORIZED
    assert auth_endpoint_response.json() == expected_json
