"""TestUtil.py - Utility methods for test cases"""
import os.path
import logging
import requests
import uuid
from flask import Flask, make_response
from flask_jwt_extended import JWTManager, create_access_token, \
     create_refresh_token, get_csrf_token, set_access_cookies
from http import cookiejar

LOGGER = logging.getLogger()

APP = Flask(__name__)
APP.config['SECRET_KEY'] = 'Testing'
APP.config['JWT_COOKIE_CSRF_PROTECT'] = True
APP.config['JWT_TOKEN_LOCATION'] = ['cookies']
JWT = JWTManager(APP)

# Set base URL, which will should only vary by port number
BASE_URL = 'http://' + os.environ['TEST_HOST'] + ':' + os.environ['APPSERVER_SPORT'] + '{{ smoacks_api_path }}'

class AcceptAll(cookiejar.CookiePolicy):
    return_ok = set_ok = domain_return_ok = path_return_ok = lambda self, *args, **kwargs: True
    netscape = True
    rfc2965 = hide_cookie2 = False

@JWT.user_claims_loader
def add_claims_to_access_token(identity):
    return {
        'user_id': identity,
        'groups': ['Testing']
    }

# This method attempts to generate valid Flask-JWT-Extended tokens, and set them
# in the session cookiejar to simulate a valid Flask-JWT-Extended session. Part of
# the approach came from this stackoverflow answer
# https://stackoverflow.com/questions/17224054/how-to-add-a-cookie-to-the-cookiejar-in-python-requests-library
def get_active_session():
    my_session = requests.session()
    access_token = None
    csrf_token = None
    my_identity = uuid.UUID(bytes=uuid.uuid4().bytes)
    with APP.app_context():
        access_token = create_access_token(identity=my_identity)
        refresh_token = create_refresh_token(identity=my_identity)
        csrf_token = get_csrf_token(access_token)
        csrf_refresh_token = get_csrf_token(refresh_token)
    print('access_token: ', str(access_token))
    print('csrf_token: ', str(csrf_token))
    print('refresh_token: ', str(refresh_token))
    print('csrf_refresh_token: ', str(csrf_refresh_token))
    my_access_cookie = requests.cookies.create_cookie(name='access_token_cookie', value=access_token, domain=os.environ['TEST_HOST'])
    my_session.cookies.set_cookie(my_access_cookie)
    my_refresh_cookie = requests.cookies.create_cookie(name='refresh_token_cookie', value=refresh_token, domain=os.environ['TEST_HOST'])
    my_session.cookies.set_cookie(my_refresh_cookie)
    return {
        'session': my_session,
        'csrf_token': csrf_token,
        'csrf_refresh_token': csrf_refresh_token
    }

def get_refresh_session():
    my_session = requests.session()

def get_new_session():
    """Sets up a new session object that contains a requests session and a saved csrf token"""
    my_session = requests.session()
    my_session.cookies.set_policy(AcceptAll())
    return {
        'session': my_session,
        'csrf_token': None,
        'csrf_refresh_token': None
    }

def log_response_error(resp, log_success=False):
    """Shared method for logging response errors"""
    if resp.status_code >= 400 or log_success:
        LOGGER.debug('Response text = %s', resp.text)

def get_response_with_jwt(test_session, method, url, payload=None, use_refresh_csrf=False):
    """Returns response for desired method with optional payload, adding JWT auth"""
    # If test_session is defined, then use it, otherwise use requests
    req = test_session['session'] if test_session else requests
    args = {}
    if method == 'PUT' or method == 'POST':
        args['json'] = payload
    if test_session and (test_session['csrf_token'] or test_session['csrf_refresh_token']):
        if use_refresh_csrf:
            args['headers'] = {'X-CSRF-TOKEN': test_session['csrf_refresh_token']}
        else:
            args['headers'] = {'X-CSRF-TOKEN': test_session['csrf_token']}
    LOGGER.debug("\nBase URL:\n" + str(BASE_URL))
    LOGGER.debug('args = ' + str(args))
    resp = None
    if method == 'GET':
        resp = req.get(BASE_URL + url, **args)
    elif method == 'PUT':
        resp = req.put(BASE_URL + url, **args)
    elif method == 'POST':
        resp = req.post(BASE_URL + url, **args)
    elif method == 'DELETE':
        resp = req.delete(BASE_URL + url, **args)
    if resp and test_session and 'csrf_access_token' in resp.cookies:
        test_session['csrf_token'] = resp.cookies['csrf_access_token']
    if resp and test_session and 'csrf_refresh_token' in resp.cookies:
        test_session['csrf_refresh_token'] = resp.cookies['csrf_refresh_token']
    return resp
