# coding: utf-8
from __future__ import unicode_literals

import glob
import os.path

from fabric import api
from fabric import context_managers as context
from fabric.contrib.console import confirm


api.env['dumps'] = 'dumps'
api.env['sqlitename'] = 'db.sqlite3'


@api.task
def push(version=None):
    """Push master and develop branches to origin."""
    api.local('git checkout develop')
    if version is None:
        version = next_version()
    for package in ('intback', 'extback', 'celery'):
        api.local(
            'docker tag bugbounty_{0} registry.yandex.net/bugbounty/{0}:{1}'.format(package, version))
        api.local(
            'docker push registry.yandex.net/bugbounty/{0}:{1}'.format(package, version))


@api.task
def build(version=None):
    """Build Docker images"""
    api.local('git checkout release-{0}'.format(version))
    api.local('make build')


@api.task
def full_build(version=None):
    """Build and push Docker images"""
    if version is None:
        version = next_version()
    release(version)
    build(version)
    if confirm('Push changes?'):
        push(version)


def next_version():
    last_version = get_last_version()
    last_version[-1] += 1
    return '.'.join(str(component) for component in last_version)


def get_last_version():
    output = api.local('git tag', capture=True)
    return max(parse_versions(output))


def parse_versions(output):
    for line in output.split('\n'):
        if not line:
            continue
        yield list(numeric_version(line))


def numeric_version(version_string):
    for item in version_string.rstrip().split('.'):
        yield int(item)


@api.task
def backup(version):
    dumps = api.env.get('dumps')
    sqlitename = api.env.get('sqlitename')
    if not(os.path.exists(dumps) and os.path.isdir(dumps)):
        return
    with context.lcd(dumps):
        source = os.path.join(os.path.pardir, sqlitename)
        destination = '00{0}_{1}'.format(version, sqlitename)
        api.local('cp {0} {1}'.format(source, destination))


@api.task
def restore():
    dumps = api.env.get('dumps')
    sqlitename = api.env.get('sqlitename')
    if not(os.path.exists(dumps) and os.path.isdir(dumps)):
        return
    with context.lcd(dumps):
        files = glob.glob('*_db.sqlite3').sort()
        latest = files.pop()
        api.local('cp {0} {1}'.format(latest, os.path.join(os.path.pardir, sqlitename)))


@api.task
def new_build_and_push(application=None, version='latest'):
    apps = list(COMPONENTS_DICT)
    if application and application in apps:
        apps = [application]
    for image in apps:
        api.local('docker-compose build {0}'.format(image))
        api.local('docker tag bugbounty_{0} registry.yandex.net/bugbounty/{0}:{1}'.format(image, version))
        api.local('docker push registry.yandex.net/bugbounty/{0}:{1}'.format(image, version))


COMPONENTS_DICT = {
    'extback': ['extback'],
    'intback': ['intback', 'celery'],
}


APPLICATIONS_DICT = {
    'extback': 'bugbounty-external-backend',
    'intback': 'bugbounty-internal-backend',
}


DOCKERFILES_DICT = {
    'extback': 'Dockerfile.external',
    'intback': 'Dockerfile.internal',
}

TRANSLATIONS_DICT = {
    'extback': ('tests-external', 'external'),
    'intback': ('tests-internal', 'internal'),
}


@api.task
def deploy(application=None, version=None, comment=None):
    if application is None:
        apps = COMPONENTS_DICT.keys()
    else:
        apps = [application] if application in COMPONENTS_DICT else []
    for app in apps:
        command = 'releaser deploy --qloudinst=ext --project=tools --applications={} --components={} --image={}'.format(
            APPLICATIONS_DICT[app], ','.join(COMPONENTS_DICT[app]), app
        )
        if version:
            command += ' -v {}'.format(version)
        if comment:
            command += ' --deploy-comment-format="{}"'.format(comment)
        api.local(command)


@api.task
def release(application=None):
    if application is not None and application not in COMPONENTS_DICT:
        print('application possible values: {}'.format(', '.join(COMPONENTS_DICT.keys())))
        return
    api.local('releaser changelog')
    api.local('releaser vcs_commit')
    api.local('releaser vcs_tag')
    for component, dockerfile in DOCKERFILES_DICT.items():
        api.local('releaser build -i {} -f {}'.format(component, dockerfile))
    for component in DOCKERFILES_DICT.keys():
        api.local('releaser push -i {}'.format(component))
    api.local('releaser vcs_push --remote=origin')
    deploy(application)


@api.task
def download_translations(token, application=None):
    if application is None:
        apps = TRANSLATIONS_DICT.keys()
    else:
        apps = [application] if application in TRANSLATIONS_DICT else []

    for app in apps:
        service, keyset = TRANSLATIONS_DICT[app]
        args = (
            '--id bugbounty',
            '--branch master',
            '--language en',
            '--language ru',
            '--keyset {}'.format(keyset),
            '--token "OAuth {}"'.format(token),
            '--use-testing 0',
            '--unapprove',
        )
        args_string = ' '.join(args)
        command = 'python manage.py tankerdownload {} && python manage.py compilemessages'.format(args_string)
        api.local('docker-compose build {service}'.format(service=service))
        api.local("docker-compose run {service} bash -c '{command}'".format(service=service, command=command))
