"""Models for manipulating images in/to/from storage."""
import collections
import functools
import json


class Image(collections.UserDict):
    """Model for an Image."""

    def __init__(self, client, id, data):
        """Construct Image Model."""
        super(Image, self).__init__(data)
        for k, v in data.items():
            setattr(self, k, v)

        self._id = id
        self._client = client

        assert self._id == self.id,\
            'Requested image id({}) does not match store id({})'.format(
                self._id, self.id
            )

    def __getitem__(self, key):
        """Get items from parent dict."""
        return super().__getitem__(key)

    def export(self, dest, compressed=False):
        """Write image to dest, return True on success."""
        with self._client() as podman:
            results = podman.ExportImage(self.id, dest, compressed)
        return results['image']

    def history(self):
        """Retrieve image history."""
        with self._client() as podman:
            for r in podman.HistoryImage(self.id)['history']:
                yield collections.namedtuple('HistoryDetail', r.keys())(**r)

    def _lower_hook(self):
        """Convert all keys to lowercase."""

        @functools.wraps(self._lower_hook)
        def wrapped(input):
            return {k.lower(): v for (k, v) in input.items()}

        return wrapped

    def inspect(self):
        """Retrieve details about image."""
        with self._client() as podman:
            results = podman.InspectImage(self.id)
            obj = json.loads(results['image'], object_hook=self._lower_hook())
            return collections.namedtuple('ImageInspect', obj.keys())(**obj)

    def push(self, target, tlsverify=False):
        """Copy image to target, return id on success."""
        with self._client() as podman:
            results = podman.PushImage(self.id, target, tlsverify)
        return results['image']

    def remove(self, force=False):
        """Delete image, return id on success.

        force=True, stop any running containers using image.
        """
        with self._client() as podman:
            results = podman.RemoveImage(self.id, force)
        return results['image']

    def tag(self, tag):
        """Tag image."""
        with self._client() as podman:
            results = podman.TagImage(self.id, tag)
        return results['image']


class Images(object):
    """Model for Images collection."""

    def __init__(self, client):
        """Construct model for Images collection."""
        self._client = client

    def list(self):
        """List all images in the libpod image store."""
        with self._client() as podman:
            results = podman.ListImages()
        for img in results['images']:
            yield Image(self._client, img['id'], img)

    def create(self, *args, **kwargs):
        """Create image from configuration."""
        with self._client() as podman:
            results = podman.CreateImage()
        return results['image']

    def create_from(self, *args, **kwargs):
        """Create image from container."""
        # TODO: Should this be on container?
        with self._client() as podman:
            results = podman.CreateFromContainer()
        return results['image']

    def build(self, *args, **kwargs):
        """Build container from image.

        See podman-build.1.md for kwargs details.
        """
        with self._client() as podman:
            # TODO: Need arguments
            podman.BuildImage()

    def delete_unused(self):
        """Delete Images not associated with a container."""
        with self._client() as podman:
            results = podman.DeleteUnusedImages()
        return results['images']

    def import_image(self, source, reference, message=None, changes=None):
        """Read image tarball from source and save in image store."""
        with self._client() as podman:
            results = podman.ImportImage(source, reference, message, changes)
        return results['image']

    def pull(self, source):
        """Copy image from registry to image store."""
        with self._client() as podman:
            results = podman.PullImage(source)
        return results['id']

    def search(self, id, limit=25):
        """Search registries for id."""
        with self._client() as podman:
            results = podman.SearchImage(id)
        for img in results['images']:
            yield img