import logging
import string
import shutil
import os
import hashlib

from datetime import datetime, timedelta
from flask import url_for

import storage

from data.database import initialize_db
from data import model
from app import app


logger = logging.getLogger(__name__)
store = storage.load()
logging.basicConfig(**app.config['LOGGING_CONFIG'])


SAMPLE_DIFFS = ['test/data/sample/diffs/diffs%s.json' % i
                for i in range(1, 10)]

REFERENCE_DATE = datetime(2013, 6, 23)


def __gen_checksum(image_id):
  h = hashlib.md5(image_id)
  return 'tarsum+sha256:' + h.hexdigest() + h.hexdigest()


def __gen_image_id(repo, image_num):
  str_to_hash = "%s/%s/%s" % (repo.namespace, repo.name, image_num)

  h = hashlib.md5(str_to_hash)
  return h.hexdigest() + h.hexdigest()


global_image_num = [0]
def create_subtree(repo, structure, parent):
  num_nodes, subtrees, last_node_tags = structure

  # create the nodes
  for i in range(num_nodes):
    image_num = global_image_num[0]
    global_image_num[0] += 1
    docker_image_id = __gen_image_id(repo, image_num)
    logger.debug('new docker id: %s' % docker_image_id)
    checksum = __gen_checksum(docker_image_id)

    new_image = model.create_image(docker_image_id, repo)
    model.set_image_checksum(docker_image_id, repo, checksum)

    creation_time = REFERENCE_DATE + timedelta(days=image_num)
    new_image = model.set_image_metadata(docker_image_id, repo.namespace,
                                         repo.name, str(creation_time),
                                         'no comment', parent)

    # Populate the diff file
    diff_path = store.image_file_diffs_path(repo.namespace, repo.name,
                                            docker_image_id)
    source_diff = SAMPLE_DIFFS[image_num % len(SAMPLE_DIFFS)]

    with open(source_diff, 'r') as source_file:
      store.stream_write(diff_path, source_file)

    parent = new_image

  if last_node_tags:
    if not isinstance(last_node_tags, list):
      last_node_tags = [last_node_tags]

    for tag_name in last_node_tags:
      model.create_or_update_tag(repo.namespace, repo.name, tag_name,
                                 new_image.docker_image_id)

  for subtree in subtrees:
    create_subtree(repo, subtree, new_image)


def __generate_repository(user, name, description, is_public, permissions,
                          structure):
  repo = model.create_repository(user.username, name, user)

  if is_public:
    model.set_repository_visibility(repo, 'public')

  if description:
    repo.description = description
    repo.save()

  for delegate, role in permissions:
    model.set_user_repo_permission(delegate.username, user.username, name,
                                   role)

  create_subtree(repo, structure, None)

  return repo


if __name__ == '__main__':
  initialize_db()

  if app.config.get('POPULATE_DB_TEST_DATA', False):
    logger.debug('Populating the DB with test data.')

    new_user_1 = model.create_user('devtable', 'password',
                                   'jschorr@devtable.com')
    new_user_1.verified = True
    new_user_1.save()

    new_user_2 = model.create_user('public', 'password',
                                   'jacob.moshenko@gmail.com')
    new_user_2.verified = True
    new_user_2.save()

    __generate_repository(new_user_1, 'simple', 'Simple repository.', False,
                          [], (4, [], ['latest', 'prod']))

    __generate_repository(new_user_1, 'complex',
                          'Complex repository with many branches and tags.',
                          False, [(new_user_2, 'read')],
                          (2, [(3, [], 'v2.0'),
                               (1, [(1, [(1, [], ['prod'])],
                                     'staging'),
                                    (1, [], None)], None)], None))

    __generate_repository(new_user_1, 'gargantuan', None, False, [],
                          (2, [(3, [], 'v2.0'),
                               (1, [(1, [(1, [], ['latest', 'prod'])],
                                     'staging'),
                                    (1, [], None)], None),
                               (20, [], 'v3.0'),
                               (5, [], 'v4.0'),
                               (1, [(1, [], 'v5.0'), (1, [], 'v6.0')], None)],
                           None))

    __generate_repository(new_user_2, 'publicrepo',
                          'Public repository pullable by the world.', True,
                          [], (10, [], 'latest'))

    __generate_repository(new_user_1, 'shared',
                          'Shared repository, another user can write.', False,
                          [(new_user_2, 'write')], (5, [], 'latest'))

    building = __generate_repository(new_user_1, 'building',
                                     'Empty repository which is building.',
                                     False, [], (0, [], None))


    org = model.create_organization('devtableorg', 'quay@devtable.com',
                                    new_user_1)

    org_repo = __generate_repository(org, 'orgrepo',
                                     'Repository owned by an org.', False,
                                     [], (4, [], ['latest', 'prod']))

    reader_team = model.create_team('readers', org, 'member',
                                    'Readers of orgrepo.')
    model.set_team_repo_permission(reader_team.name, org_repo.namespace,
                                   org_repo.name, 'read')
    model.add_user_to_team(new_user_2, reader_team)

    token = model.create_access_token(building, 'write')
    tag = 'ci.devtable.com:5000/%s/%s' % (building.namespace, building.name)
    build = model.create_repository_build(building, token, '123-45-6789', tag)

    build.build_node_id = 1
    build.phase = 'building'
    build.status_url = 'http://localhost:5000/test/build/status'
    build.save()