import sys
import requests
import dotenv
from functools import wraps
from datetime import datetime, timedelta
import os
import logging
from .base_url_session import BaseURLSession
logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
logger = logging.getLogger(__name__)


dotenv.load_dotenv()

tokenUrl = ''


def get_or_refresh(func):
    '''This is a decorator that handles the in-memory caching of the token and
    refreshing when necessary.
    '''
    token = None
    expires_at = None

    @wraps(func)
    def wrapper(*args, **kwargs):
        nonlocal token
        nonlocal expires_at
        requests_session = kwargs.get('requests_session_cls', requests.Session())

        if not token or datetime.now() >= expires_at:
            logger.debug('getting a new token')
            token = func(*args, **kwargs)

            if not token:
                logger.error('could not fetch token')

                return
            offset = timedelta(seconds=token['expires_in'])
            # set the expiration time to now + expires_in(seconds) - 60 seconds
            # this gives a little bit of a buffer
            expires_at = datetime.now() + offset - timedelta(seconds=60)

        access_token = token['access_token']
        print('access_token', access_token)
        requests_session.headers.update({'Authorization': f'Bearer {access_token}'})

        return requests_session

    return wrapper


@get_or_refresh
def get_token(client_id=None, client_secret=None,
              audience=None, token_url=None, **kwargs):
    '''This script assumes that the `requests` library is installed and that
    the `OAUTH2_CLIENT_ID` `OAUTH2_CLIENT_SECRET`, `OAUTH2_API_AUDIENCE`, and
    `OAUTH2_TOKEN_URL` values are all defined as environmental variables. They
    can also be passed into this function as keyword values.
    >>> from client_exchange import get_token
    >>> token = get_token()

    '''

    payload = {
        'grant_type': 'client_credentials',
        'client_id': os.getenv('OAUTH2_CLIENT_SECRET', client_id),
        'client_secret': os.getenv('OAUTH2_CLIENT_SECRET', client_secret),
        # 'audience': os.getenv('OAUTH2_API_AUDIENCE', 'audience')
    }

    overridable_options = ['audience', 'scope', 'username', 'session_id']
    overridable_options.extend(payload.keys())

    for opt in filter(lambda o: o in kwargs, overridable_options):
        payload[opt] = kwargs[opt]

    # token_url can be overriden
    token_url = os.getenv('OAUTH2_TOKEN_URL', token_url)
    logger.debug('token_url: %s', token_url)
    res = None
    try:
        res = requests.post(token_url, data=payload)

        if res:
            return res.json()
    except Exception as exc:
        logger.error(exc)

    logger.error(res)


get_token_client_credentials = get_token

@get_or_refresh
def get_token_password(client_id=None, client_secret=None,
                       audience=None, username=None,
                       password=None, token_url=None, **kwargs):
    # creds = (SERVICENOW_CLIENT_ID, SERVICENOW_CLIENT_SECRET)
    payload = {
        'grant_type': 'password',
        'client_id': client_id,
        'client_secret': client_secret,
        'username': username,
        'password': password
    }
    response = requests.post(token_url,
                             data=payload)
                             # data={'grant_type': 'client_credentials'})

    print('response', response.json())

    return response.json()['access_token']

