import copy
from unittest import mock

import docker
from docker.constants import DEFAULT_DOCKER_API_VERSION

from . import fake_api


class CopyReturnMagicMock(mock.MagicMock):
    """
    A MagicMock which deep copies every return value.
    """
    def _mock_call(self, *args, **kwargs):
        ret = super()._mock_call(*args, **kwargs)
        if isinstance(ret, (dict, list)):
            ret = copy.deepcopy(ret)
        return ret


def make_fake_api_client(overrides=None):
    """
    Returns non-complete fake APIClient.

    This returns most of the default cases correctly, but most arguments that
    change behaviour will not work.
    """

    if overrides is None:
        overrides = {}
    api_client = docker.APIClient(version=DEFAULT_DOCKER_API_VERSION)
    mock_attrs = {
        'build.return_value': fake_api.FAKE_IMAGE_ID,
        'commit.return_value': fake_api.post_fake_commit()[1],
        'containers.return_value': fake_api.get_fake_containers()[1],
        'create_container.return_value':
            fake_api.post_fake_create_container()[1],
        'create_host_config.side_effect': api_client.create_host_config,
        'create_network.return_value': fake_api.post_fake_network()[1],
        'create_secret.return_value': fake_api.post_fake_secret()[1],
        'create_config.return_value': fake_api.post_fake_config()[1],
        'exec_create.return_value': fake_api.post_fake_exec_create()[1],
        'exec_start.return_value': fake_api.post_fake_exec_start()[1],
        'images.return_value': fake_api.get_fake_images()[1],
        'inspect_container.return_value':
            fake_api.get_fake_inspect_container()[1],
        'inspect_image.return_value': fake_api.get_fake_inspect_image()[1],
        'inspect_network.return_value': fake_api.get_fake_network()[1],
        'logs.return_value': [b'hello world\n'],
        'networks.return_value': fake_api.get_fake_network_list()[1],
        'start.return_value': None,
        'wait.return_value': {'StatusCode': 0},
        'version.return_value': fake_api.get_fake_version()
    }
    mock_attrs.update(overrides)
    mock_client = CopyReturnMagicMock(**mock_attrs)

    mock_client._version = docker.constants.DEFAULT_DOCKER_API_VERSION
    return mock_client


def make_fake_client(overrides=None):
    """
    Returns a Client with a fake APIClient.
    """
    client = docker.DockerClient(version=DEFAULT_DOCKER_API_VERSION)
    client.api = make_fake_api_client(overrides)
    return client
