# -*- coding: utf-8 -*-
""" Helpers for related docker commands. """
from __future__ import absolute_import, unicode_literals

# local imports
from . import conf
from . import log
from . import shell
from . import versioning


class RegistryClient(object):
    """ Helper class for talking to docker registry. """
    def __init__(self, registry, username, password):
        self.user = username
        self.pw = password
        self.auth = (username, password)
        self.registry_url = 'https://' + registry

    def get(self, *args, **kw):
        """ Proxy over requests.get

        Do not include requests globally so it's not required to build and
        push images. Otherwise, the project needs to install requests even
        when not using registry in any way.
        """
        import requests
        return requests.get(*args, **kw)

    def list_images(self):
        """ List images stored in the registry.

        :return List[str]:
            List of image names.
        """
        r = self.get(self.registry_url + '/v2/_catalog', auth=self.auth)
        return r.json()['repositories']

    def list_tags(self, image_name):
        """ List all tags for the given image stored in the registry.

        :param str image_name:
            The name of the image to query. The image must be present on the
            registry for this call to return any values.
        :return List[str]:
            List of tags for that image.
        """
        tags_url = self.registry_url + '/v2/{}/tags/list'

        r = self.get(tags_url.format(image_name), auth=self.auth)
        data = r.json()

        if 'tags' in data:
            return reversed(sorted(data['tags']))

        return []


def build_image(registry, image):
    """ Build docker image.

    :param str registry:
        The name of the registry this image belongs to. If not given, the
        resulting image will have a name without the registry.
    :param Dict image:
        The dict containing the information about the built image. This is the
        same dictionary as defined in DOCKER_IMAGES variable.
    """
    if ':' in image['name']:
        name, tag = image['name'].split(':', 1)
    else:
        name, tag = image['name'], None

    values = {
        'registry': '' if registry is None else registry + '/',
        'image': name,
        'tag': tag,
        'version': versioning.current(),
    }

    if tag is not None:
        args = [
            '-t {registry}{image}:{tag}'.format(**values),
        ]
    else:
        args = [
            '-t {registry}{image}'.format(**values),
            '-t {registry}{image}:{version}'.format(**values),
        ]

    if 'file' in image:
        args.append('-f {}'.format(conf.proj_path(image['file'])))

    with conf.within_proj_dir(image.get('path', '.')):
        log.info("Building <33>{registry}<35>/{image}".format(**values))
        shell.run('docker build {args} .'.format(args=' '.join(args)))


def push_image(registry, image):
    """ Push the given image to selected repository.

    :param str registry:
        The name of the registry we're pushing to. This is the address of the
        repository without the protocol specification (no http(s)://)
    :param Dict image:
        The dict containing the information about the image. This is the same
        dictionary as defined in DOCKER_IMAGES variable.
    """
    values = {
        'registry': registry,
        'image': image['name'],
    }

    log.info("Pushing <33>{registry}<35>/{image}".format(**values))
    shell.run('docker push {registry}/{image}'.format(**values))
