import argparse
import logging

from data import model
from data.database import ImageStoragePlacement, ImageStorageLocation
from app import storage


logger = logging.getLogger(__name__)


PATHSPECS = [
  (storage.image_json_path, True),
  (storage.image_layer_path, True),
  (storage.image_ancestry_path, True),
  (storage.image_file_trie_path, False),
  (storage.image_file_diffs_path, False),
]


def migrate_image(image, destination_location):
  logger.debug('Migrating image: %s -> %s', image.docker_image_id, destination_location.name)
  destination_location_set = {destination_location.name}

  for path_func, required in PATHSPECS:
    path = path_func(image.storage.uuid)

    if storage.exists(image.storage.locations, path):
      if not storage.exists(destination_location_set, path):
        logger.debug('Migrating path: %s', path)

        with storage.stream_read_file(image.storage.locations, path) as file_to_migrate:
          storage.stream_write(destination_location_set, path, file_to_migrate)
      else:
        logger.debug('File already present in destination: %s', path)
    elif required:
      raise RuntimeError('Required file not present in image to migrate: %s', path)

  # Successfully migrated, now write the placement
  ImageStoragePlacement.create(location=destination_location, storage=image.storage)

parser = argparse.ArgumentParser(description='Replicate an image storage.')
parser.add_argument('--namespace', type=str, required=True,
                    help='Namespace for the repository containing the image to be replicated')
parser.add_argument('--repository', type=str, required=True,
                    help='Name for the repository containing the image to be replicated')
parser.add_argument('--imageid', type=str, default=None,
                    help='Specific image to migrate, entire repo will be migrated if omitted')
parser.add_argument('--to', type=str, required=True,
                    help='Storage region to which the data should be replicated')

if __name__ == "__main__":
  logging.basicConfig(level=logging.DEBUG)
  logging.getLogger('boto').setLevel(logging.CRITICAL)

  args = parser.parse_args()

  location = ImageStorageLocation.get(name=args.to)

  images = []
  if args.imageid is not None:
    images = [model.get_image_by_id(args.namespace, args.repository, args.imageid)]
  else:
    images = model.get_repository_images(args.namespace, args.repository)

  for img in images:
    migrate_image(img, location)
