import json

from six.moves import urllib

from dcos import config, cosmos, http, packagemanager, rpcclient, util
from dcos.errors import DCOSException

logger = util.get_logger(__name__)

EMBED_ACTIVE_RUNS = 'activeRuns'
EMBED_SCHEDULES = 'schedules'
EMBED_HISTORY = 'history'
EMBED_HISTORY_SUMMARY = 'historySummary'


def create_client(toml_config=None):
    """Creates a Metronome client with the supplied configuration.

    :param toml_config: configuration dictionary
    :type toml_config: config.Toml
    :returns: Metronome client
    :rtype: dcos.metronome.Client
    """

    if toml_config is None:
        toml_config = config.get_config()

    metronome_url = _get_metronome_url(toml_config)
    timeout = config.get_config_val('core.timeout') or http.DEFAULT_TIMEOUT
    rpc_client = rpcclient.create_client(metronome_url, timeout)

    logger.info('Creating metronome client with: %r', metronome_url)
    return Client(rpc_client)


def _get_embed_query_string(embed_list):
    return '?{}'.format('&'.join('embed=%s' % (item) for item in embed_list))


def _get_metronome_url(toml_config=None):
    """
    :param toml_config: configuration dictionary
    :type toml_config: config.Toml
    :returns: metronome base url
    :rtype: str
    """
    if toml_config is None:
        toml_config = config.get_config()

    metronome_url = config.get_config_val('metronome.url', toml_config)
    if metronome_url is None:
        # dcos must be capable to use dcos_url
        _check_capability()
        dcos_url = config.get_config_val('core.dcos_url', toml_config)
        if dcos_url is None:
            raise config.missing_config_exception(['core.dcos_url'])
        metronome_url = urllib.parse.urljoin(dcos_url, 'service/metronome/')

    return metronome_url


class Client(object):
    """Class for talking to the Metronome server.

    :param rpc_client: provides a method for making HTTP requests
    :type rpc_client: _RpcClient
    """

    def __init__(self, rpc_client):
        self._rpc = rpc_client

    def get_about(self):
        """Returns info about Metronome instance

        :returns Metronome information
        :rtype: dict
        """

        response = self._rpc.http_req(http.get, 'v1/info')

        return response.json()

    def get_job(self, job_id, embed_with=None):
        """Returns a representation of the requested job.

        :param job_id: the ID of the application
        :type job_id: str
        :param embed_with: list of strings to ?embed=str&embed=str2...
        :type embed_with: [str]
        :returns: the requested Metronome job
        :rtype: dict
        """
        # refactor util name it isn't marathon specific
        job_id = util.normalize_marathon_id_path(job_id)
        embeds = _get_embed_query_string(embed_with) if embed_with else None
        url = ('v1/jobs{}{}'.format(job_id, embeds)
               if embeds else 'v1/jobs{}'.format(job_id))
        response = self._rpc.http_req(http.get, url)
        return response.json()

    def get_jobs(self, embed_with=None):
        """Get a list of known jobs.

        :param embed_with: list of strings to ?embed=str&embed=str2...
        :type embed_with: [str]
        :returns: list of known jobs
        :rtype: [dict]
        """
        embeds = _get_embed_query_string(embed_with) if embed_with else None
        url = 'v1/jobs{}'.format(embeds) if embeds else 'v1/jobs'
        response = self._rpc.http_req(http.get, url)
        return response.json()

    def add_job(self, job_resource):
        """Add a new job.

        :param job_resource: job resource
        :type job_resource: dict, bytes or file
        :returns: the job description
        :rtype: dict
        """

        # The file type exists only in Python 2, preventing type(...) is file.
        if hasattr(job_resource, 'read'):
            job_json = json.load(job_resource)
        else:
            job_json = job_resource

        response = self._rpc.http_req(http.post, 'v1/jobs', json=job_json)
        # need deployment ID
        return response.json()

    def _update_req(
            self, resource_type, resource_id, resource_json, force=False):
        """Send an HTTP request to update an application, group, or pod.

        :param resource_type: one of 'apps', 'groups', or 'pods'
        :type resource_type: str
        :param resource_id: the app, group, or pod ID
        :type resource_id: str
        :param resource_json: the json payload
        :type resource_json: {}
        :param force: whether to override running deployments