"""Helper functions for working with Credentials."""
from __future__ import unicode_literals

import logging

from django.conf import settings
from edx_rest_api_client.client import EdxRestApiClient

from openedx.core.djangoapps.catalog.utils import get_programs
from openedx.core.djangoapps.credentials.models import CredentialsApiConfig
from openedx.core.lib.edx_api_utils import get_edx_api_data
from openedx.core.lib.token_utils import JwtBuilder

log = logging.getLogger(__name__)


def get_credentials_api_client(user):
    """ Returns an authenticated Credentials API client. """

    scopes = ['email', 'profile']
    expires_in = settings.OAUTH_ID_TOKEN_EXPIRATION
    jwt = JwtBuilder(user).build_token(scopes, expires_in)
    return EdxRestApiClient(CredentialsApiConfig.current().internal_api_url, jwt=jwt)


def get_credentials(user, program_uuid=None):
    """
    Given a user, get credentials earned from the credentials service.

    Arguments:
        user (User): The user to authenticate as when requesting credentials.

    Keyword Arguments:
        program_uuid (str): UUID of the program whose credential to retrieve.

    Returns:
        list of dict, representing credentials returned by the Credentials
        service.
    """
    credential_configuration = CredentialsApiConfig.current()

    querystring = {'username': user.username, 'status': 'awarded'}

    if program_uuid:
        querystring['program_uuid'] = program_uuid

    # Bypass caching for staff users, who may be generating credentials and
    # want to see them displayed immediately.
    use_cache = credential_configuration.is_cache_enabled and not user.is_staff
    cache_key = credential_configuration.CACHE_KEY + '.' + user.username if use_cache else None
    api = get_credentials_api_client(user)

    return get_edx_api_data(
        credential_configuration, 'credentials', api=api, querystring=querystring, cache_key=cache_key
    )


def get_programs_for_credentials(programs_credentials):
    """ Given a user and an iterable of credentials, get corresponding programs
    data and return it as a list of dictionaries.

    Arguments:
        programs_credentials (list): List of credentials awarded to the user
            for completion of a program.

    Returns:
        list, containing programs dictionaries.
    """
    certified_programs = []
    programs = get_programs()
    for program in programs:
        for credential in programs_credentials:
            if program['uuid'] == credential['credential']['program_uuid']:
                program['credential_url'] = credential['certificate_url']
                certified_programs.append(program)

    return certified_programs


def get_user_program_credentials(user):
    """Given a user, get the list of all program credentials earned and returns
    list of dictionaries containing related programs data.

    Arguments:
        user (User): The user object for getting programs credentials.

    Returns:
        list, containing programs dictionaries.
    """
    programs_credentials_data = []
    credential_configuration = CredentialsApiConfig.current()
    if not credential_configuration.is_learner_issuance_enabled:
        log.debug('Display of certificates for programs is disabled.')
        return programs_credentials_data

    credentials = get_credentials(user)
    if not credentials:
        log.info('No credential earned by the given user.')
        return programs_credentials_data

    programs_credentials = []
    for credential in credentials:
        try:
            if 'program_uuid' in credential['credential']:
                programs_credentials.append(credential)
        except KeyError:
            log.exception('Invalid credential structure: %r', credential)

    if programs_credentials:
        programs_credentials_data = get_programs_for_credentials(programs_credentials)

    return programs_credentials_data


def get_programs_credentials(user):
    """Return program credentials data required for display.

    Given a user, find all programs for which certificates have been earned
    and return list of dictionaries of required program data.

    Arguments:
        user (User): user object for getting programs credentials.

    Returns:
        list of dict, containing data corresponding to the programs for which
        the user has been awarded a credential.
    """
    programs_credentials = get_user_program_credentials(user)
    credentials_data = []
    for program in programs_credentials:
        try:
            program_data = {
                'display_name': program['title'],
                'subtitle': program['subtitle'],
                'credential_url': program['credential_url'],
            }
            credentials_data.append(program_data)
        except KeyError:
            log.warning('Program structure is invalid: %r', program)

    return credentials_data
