import base64
import json

from cattle import ApiError
from common_fixtures import *  # NOQA
from datetime import timedelta
import time


def test_container_create_count(client, context):
    cs = client.create_container(imageUuid=context.image_uuid,
                                 count=3)

    assert len(cs) == 3

    for c in cs:
        c = client.wait_success(c)
        assert c.state == 'running'


def test_conatiner_simple_start(context):
    context.create_container()


def test_container_build(super_client, context, client):
    container = context.create_container(build={
        'dockerfile': 'test/Dockerfile',
        'remote': 'http://example.com',
        'rm': True,
    })

    assert container.build.dockerfile == 'test/Dockerfile'
    assert container.build.remote == 'http://example.com'
    assert container.build.rm

    image = super_client.reload(container).image()
    assert image.data.fields.build.dockerfile == 'test/Dockerfile'
    assert image.data.fields.build.remote == 'http://example.com'
    assert image.data.fields.build.tag == context.image_uuid
    assert image.data.fields.build.rm


def test_container_create_only(super_client, client, context):
    uuid = "sim:{}".format(random_num())
    container = super_client.create_container(accountId=context.project.id,
                                              imageUuid=uuid,
                                              name="test",
                                              startOnCreate=False)

    assert_fields(container, {
        "type": "container",
        "allocationState": "inactive",
        "state": "creating",
        "imageUuid": uuid,
        "firstRunning": None,
    })

    container = super_client.wait_success(container)

    assert_fields(container, {
        "type": "container",
        "allocationState": "inactive",
        "state": "stopped",
        "imageUuid": uuid,
    })

    container = super_client.reload(container)

    assert container.imageId is not None
    assert container.instanceTriggeredStop == 'stop'

    image = super_client.wait_success(container.image())
    assert_fields(image, {
        "state": "active"
    })

    volumes = container.volumes()
    assert len(volumes) == 1

    root_volume = super_client.wait_success(volumes[0])
    assert_fields(root_volume, {
        "allocationState": "inactive",
        "attachedState": "active",
        "state": "inactive",
        "instanceId": container.id,
        "deviceNumber": 0,
    })

    volume_mappings = root_volume.volumeStoragePoolMaps()
    assert len(volume_mappings) == 0

    nics = container.nics()
    assert len(nics) == 1

    image = super_client.wait_success(find_one(super_client.list_image,
                                               name=uuid))
    assert_fields(image, {
        "state": "active",
        "name": uuid,
        "isPublic": False,
    })
    image_mappings = image.imageStoragePoolMaps()

    assert len(image_mappings) == 0

    return client.reload(container)


def _assert_running(container):
    assert_fields(container, {
        "allocationState": "active",
        "state": "running",
        "firstRunning": NOT_NONE
    })

    root_volume = container.volumes()[0]
    assert_fields(root_volume, {
        "state": "active"
    })

    image = root_volume.image()
    assert_fields(image, {
        "state": "active"
    })

    volume_mappings = root_volume.volumeStoragePoolMaps()
    assert len(volume_mappings) == 1

    assert_fields(volume_mappings[0], {
        "state": "active"
    })

    volume_pool = volume_mappings[0].storagePool()
    assert_fields(volume_pool, {
        "state": "active"
    })

    # image_mappings = image.imageStoragePoolMaps()
    # assert len(image_mappings) == 2
    # for image_mapping in image_mappings:
    #    assert_fields(image_mapping, {
    #        # TODO: why isn't this active?
    #        # "state": "active",
    #        "storagePoolId": volume_pool.id
    #    })

    instance_host_mappings = container.instanceHostMaps()
    assert len(instance_host_mappings) == 1

    assert_fields(instance_host_mappings[0], {
        "state": "active"
    })


def test_container_create_then_start(super_client, client, context):
    container = client.create_container(startOnCreate=False,
                                        imageUuid=context.image_uuid)
    container = client.wait_success(container)
    container = container.start()

    assert container.state == "starting"
    assert 'start' not in container
    assert 'stop' in container
    assert 'remove' not in container

    _assert_running(super_client.wait_success(container))


def test_container_first_running(client, context):
    c = client.create_container(imageUuid=context.image_uuid,
                                startOnCreate=False)
    c = client.wait_success(c)

    assert c.state == 'stopped'
    assert c.firstRunning is None

    c = client.wait_success(c.start())
    assert c.state == 'running'
    assert c.firstRunning is not None

    first = c.firstRunning

    c = client.wait_success(c.restart())
    assert c.state == 'running'
    assert c.firstRunning == first


def test_container_restart(client, super_client, context):
    container = context.create_container()

    _assert_running(super_client.reload(container))

    container = context.client.wait_success(container)
    container = container.restart()

    assert container.state == 'restarting'
    container = client.wait_success(container)
    _assert_running(super_client.reload(container))


def test_container_stop(client, super_client, context):
    container = context.create_container(name="test")
    container = client.wait_success(container)

    assert_fields(container, {
        "state": "running"
    })

    container = container.stop()

    assert_fields(container, {
        "state": "stopping"
    })

    container = client.wait_success(container)

    assert_fields(super_client.reload(container), {
        "allocationState": "active",
        "state": "stopped"
    })

    container = super_client.reload(container)
    root_volume = container.volumes()[0]
    assert_fields(root_volume, {
        "state": "inactive"
    })

    image = root_volume.image()
    assert_fields(image, {
        "state": "active"
    })

    volume_mappings = root_volume.volumeStoragePoolMaps()
    assert len(volume_mappings) == 1

    assert_fields(volume_mappings[0], {
        "state": "inactive"
    })

    volume_pool = volume_mappings[0].storagePool()
    assert_fields(volume_pool, {
        "state": "active"
    })

    image_mappings = image.imageStoragePoolMaps()
    assert len(image_mappings) == 1
    # for image_mapping in image_mappings:
    #    assert_fields(image_mapping, {
    #        # TODO: Why isn't this active
    #        # "state": "active",
    #        "storagePoolId": volume_pool.id
    #    })

    instance_host_mappings = container.instanceHostMaps()
    assert len(instance_host_mappings) == 1
    assert instance_host_mappings[0].state == 'inactive'


def _assert_removed(container):
    assert container.state == "removed"
    assert_removed_fields(container)

    volumes = container.volumes()
    assert len(volumes) == 1

    assert volumes[0].state == "removed"
    assert_removed_fields(volumes[0])

    volume_mappings = volumes[0].volumeStoragePoolMaps()
    assert len(volume_mappings) == 1
    assert volume_mappings[0].state == "inactive"

    return container


def test_container_remove(client, super_client, context):
    container = context.create_container(name="test")
    container = client.wait_success(container)
    container = client.wait_success(container.stop())

    assert container.state == "stopped"

    container = client.delete(container)

    assert container.state == "removing"

    container = client.wait_success(container)

    _assert_removed(super_client.reload(container))
    return container


def test_container_delete_while_running(client, super_client, context):
    container = context.create_container(name="test")
    container = client.wait_success(container)
    assert container.state == 'running'

    container = client.delete(container)
    assert container.state == 'stopping'

    container = client.wait_success(container)
    _assert_removed(super_client.reload(container))
    return container


def test_container_restore(client, super_client, context):
    container = test_container_remove(client, super_client, context)

    assert container.state == "removed"

    container = container.restore()

    assert container.state == "restoring"

    container = client.wait_success(container)

    assert container.state == "stopped"
    assert_restored_fields(super_client.reload(container))

    volumes = container.volumes()
    assert len(volumes) == 1

    assert volumes[0].state == "inactive"
    assert_restored_fields(super_client.reload(volumes[0]))

    volume_mappings = super_client.reload(volumes[0]).volumeStoragePoolMaps()
    assert len(volume_mappings) == 1
    assert volume_mappings[0].state == "inactive"


def test_container_purge(client, super_client, context):
    container = test_container_remove(client, super_client, context)

    assert container.state == "removed"

    # It's easier to call container.purge(), but this was to test other
    # things too

    remove_time = now() - timedelta(hours=1)
    super_client.update(container, {
        'removeTime': format_time(remove_time)
    })

    purge = super_client.list_task(name="purge.resources")[0]
    purge.execute()

    container = client.reload(container)
    for x in range(30):
        if container.state == "removed":
            time.sleep(0.5)
            container = client.reload(container)