from collections import defaultdict
from data import model
from endpoints.api.image_models_interface import (ImageInterface, ImageWithHistory, ImageWithTags,
                                                  Image)

def _image(namespace_name, repo_name, image, all_images, include_parents=True):
  parent_image_tuples = []
  if include_parents:
    parent_images = [all_images[ancestor_id] for ancestor_id in image.ancestor_id_list()
                     if all_images.get(ancestor_id)]
    parent_image_tuples = [_image(namespace_name, repo_name, parent_image, all_images, False)
                           for parent_image in parent_images]

  return Image(image.docker_image_id, image.created, image.comment, image.command,
               image.storage.image_size, image.storage.uploading, parent_image_tuples)

def _tag_names(image, tags_by_docker_id):
  return [tag.name for tag in tags_by_docker_id.get(image.docker_image_id, [])]


class PreOCIModel(ImageInterface):
  """
  PreOCIModel implements the data model for the Image API using a database schema
  before it was changed to support the OCI specification.
  """
  def get_repository_images(self, namespace_name, repo_name):
    repo = model.repository.get_repository(namespace_name, repo_name)
    if not repo:
      return None

    all_images = model.image.get_repository_images_without_placements(repo)
    all_images_map = {image.id: image for image in all_images}

    all_tags = list(model.tag.list_repository_tags(namespace_name, repo_name))

    tags_by_docker_id = defaultdict(list)
    for tag in all_tags:
      tags_by_docker_id[tag.image.docker_image_id].append(tag)

    def _build_image(image):
      image_itself = _image(namespace_name, repo_name, image, all_images_map)
      return ImageWithTags(image_itself, tag_names=_tag_names(image, tags_by_docker_id))

    return [_build_image(image) for image in all_images]

  def get_repository_image(self, namespace_name, repo_name, docker_image_id):
    image = model.image.get_repo_image_extended(namespace_name, repo_name, docker_image_id)
    if not image:
      return None

    parent_images = model.image.get_parent_images(namespace_name, repo_name, image)
    all_images_map = {image.id: image for image in parent_images}
    return ImageWithHistory(_image(namespace_name, repo_name, image, all_images_map))


pre_oci_model = PreOCIModel()