# -*- coding: utf-8; -*-
from __future__ import unicode_literals
import os
import copy
import re

import docker
import six
from six.moves.urllib.parse import urlparse
from requests.packages      import urllib3

from .const                       import DOCKER_API_VERSION, DOCKER_DEFAULT_TIMEOUT
from .container                   import Container
from .commercial_invoice.injector import Injector
from .commercial_invoice.service  import Service
from .image                       import Image
from .utils                       import utils, logger


class ContainerShip(object):
    def __init__(self, address, **kwargs):
        """
        explain me ; )

        """
        utils.validate_uri(address)
        # TODO: update me with a config file entry need to update to get the version from docker and use that.
        self.API_VERSION = DOCKER_API_VERSION
        self.url         = urlparse(address)

        if self.url.scheme == 'https':
            # TODO: Need to allow for ca to be passed if not disable warnings.
            urllib3.disable_warnings()

            for cert_name_type in ('ca', 'cert', 'key'):
                cert_path = utils.validate_path(os.path.join(kwargs['ssl_cert_path'], "{0}.pem".format(cert_name_type))) \
                    if 'ssl_cert_path' in kwargs and kwargs['ssl_cert_path'] else None
                setattr(self, 'SSL_{0}_PATH'.format(cert_name_type.upper()), cert_path)

            self.SSL_VERIFY = kwargs['verify'] if 'verify' in kwargs and isinstance(kwargs['verify'], bool) else True

            if not self.SSL_VERIFY:
                self.SSL_CA_PATH = None

            client_certs = (self.SSL_CERT_PATH, self.SSL_KEY_PATH) if self.SSL_KEY_PATH and self.SSL_CERT_PATH else None
            tls_config   = docker.tls.TLSConfig(client_cert=client_certs, ca_cert=self.SSL_CA_PATH, verify=self.SSL_VERIFY)

            self._client_session = docker.Client(self.url.geturl(), tls=tls_config, timeout=DOCKER_DEFAULT_TIMEOUT, version=self.API_VERSION)
        else:
            self._client_session = docker.Client(self.url.geturl(), timeout=DOCKER_DEFAULT_TIMEOUT, version=self.API_VERSION)

        self._docker_info = self._client_session.version()
        self._injector = None

    @property
    def injector(self):
        return self._injector

    @injector.setter
    def injector(self, value):
        if not isinstance(value, Injector):
            raise TypeError(logger.error("injector must be an instance of Injector."))

        self._injector = value

    def report(self):
        logger.info("Container Ship: {0}".format(self.url.geturl()))
        logger.info("docker-py: {0}".format(docker.version))
        logger.info("Docker Api: {0}".format(self.API_VERSION))
        logger.info("Docker Daemon:")
        for key, value in six.iteritems(self._docker_info):
            logger.info("\t {0}: {1}".format(key, value))

        logger.info("Reporting for Dispatch.")

    def healthy(self):
        # TODO: write code?
        return self._client_session.ping()

    def inspect(self):
        # TODO: build object out of returned data.
        return self._client_session.info()

    def manifest(self):
        # TODO get a list of all containers and cargo
        pass

    def recall_service(self, service):
        """
        This method assumes that its a roll back during a deployment.  If not used during a deployment session

        This method should be extended later to be more useful.
        """
        if not isinstance(service, Service):
            raise TypeError("service must be of type Service.")

        logger.warning("The deployment for {0} on {1} failed starting the rollback.".format(service.alias, self.url.geturl()))

        def anonymous(anonymous_service):
            if not isinstance(anonymous_service, Service):
                raise TypeError("service must be an instance of Service.")

            containers = self.find_previous_service_containers(anonymous_service)
            if containers:
                for name in list(anonymous_service.containers.keys()):
                    del anonymous_service.containers[name]

                anonymous_service.cargo.delete()

                for name, container in six.iteritems(containers):
                    # TODO: add function to container obj to see if its running.
                    if container.state().get('running'):
                        logger.info(
                            "is already running... Might want to investigate.",
                            extra={'formatter': 'container', 'container': container.name}
                        )
                    else:
                        if container.start():
                            logger.info(
                                "is restarted and healthy.",
                                extra={'formatter': 'container', 'container': container.name}
                            )
                        else: