import os
import sys
import json
import globus_sdk
from configobj import ConfigObj
from funcx.sdk import version

__all__ = (
    # option name constants
    'FUNCX_RT_OPTNAME',
    'FUNCX_AT_OPTNAME',
    'FUNCX_AT_EXPIRES_OPTNAME',

    'write_option',
    'lookup_option',
    'remove_option',
    'internal_auth_client',

    'check_logged_in',
    'safeprint',
    'format_output'
)

# The path to read and write servable definitions.
# FUNCX_URL = "https://funcx.org/"
# FUNCX_SERVICE_ADDRESS = "https://funcx.org/api/v1"

CONF_SECTION_NAME = 'funcx'

# CLIENT_ID = '4cf29807-cf21-49ec-9443-ff9a3fb9f81c'
FUNCX_RT_OPTNAME = 'funcx_refresh_token'
FUNCX_AT_OPTNAME = 'funcx_access_token'
FUNCX_AT_EXPIRES_OPTNAME = 'funcx_access_token_expires'

GLOBUS_ENV = os.environ.get('GLOBUS_SDK_ENVIRONMENT')
if GLOBUS_ENV:
    FUNCX_RT_OPTNAME = '{}_{}'.format(GLOBUS_ENV, FUNCX_RT_OPTNAME)
    FUNCX_AT_OPTNAME = '{}_{}'.format(GLOBUS_ENV, FUNCX_AT_OPTNAME)
    FUNCX_AT_EXPIRES_OPTNAME = '{}_{}'.format(GLOBUS_ENV,
                                               FUNCX_AT_EXPIRES_OPTNAME)
    CLIENT_ID = {
        'sandbox':      'f9e36a20-2e1a-49e5-ba67-34cc82ca8b29',
        'test':         '2aa543de-b6c6-4aa5-9d7b-ef28e3a28cd8',
        'staging':      '0811fdd3-0d3e-4b5e-b634-8d6c91d87f21',
        'preview':      '988ff3e0-3bcf-495a-9f12-3b3a309bdb36',
    }.get(GLOBUS_ENV, CLIENT_ID)


def get_config_obj():
    path = os.path.expanduser("~/.funcx/funcx.cfg")

    return ConfigObj(path, encoding='utf-8', create_empty=True)


def lookup_option(option):
    conf = get_config_obj()
    try:
        return conf[CONF_SECTION_NAME][option]
    except KeyError:
        return None


def write_option(option, value):
    """
    Write an option to disk -- doesn't handle config reloading
    """
    # deny rwx to Group and World -- don't bother storing the returned old mask
    # value, since we'll never restore it in the CLI anyway
    # do this on every call to ensure that we're always consistent about it
    os.umask(0o077)

    conf = get_config_obj()

    # add the section if absent
    if CONF_SECTION_NAME not in conf:
        conf[CONF_SECTION_NAME] = {}

    conf[CONF_SECTION_NAME][option] = value
    conf.write()


def remove_option(option):
    conf = get_config_obj()

    # if there's no section for the option we're removing, just return None
    try:
        section = conf[CONF_SECTION_NAME]
    except KeyError:
        return None

    try:
        opt_val = section[option]

        # remove value and flush to disk
        del section[option]
        conf.write()
    except KeyError:
        opt_val = None

    # return the just-deleted value
    return opt_val


def internal_auth_client():
    """
    Get the globus native app client.

    :return:
    """
    return globus_sdk.NativeAppAuthClient(CLIENT_ID, app_name=version.app_name)


def check_logged_in():
    """
    Check if the user is already logged in.

    :return:
    """
    search_rt = lookup_option(FUNCX_RT_OPTNAME)
    if search_rt is None:
        return False
    native_client = internal_auth_client()
    res = native_client.oauth2_validate_token(search_rt)
    return res['active']


def safeprint(s):
    """
    Catch print errors.

    :param s:
    :return:
    """
    try:
        print(s)
        sys.stdout.flush()
    except IOError:
        pass


def format_output(dataobject):
    """
    Use safe print to make sure jobs are correctly printed.

    :param dataobject:
    :return:
    """
    safeprint(json.dumps(dataobject, indent=2, separators=(',', ': ')))