#!/usr/bin/python
# -*- coding: utf-8 -*-

import sys
sys.path.insert(0, '/opt/direct-py/startrek-python-client-sni-fix')

import argparse
import getpass
import json
import os
import re
import requests
import shutil
import subprocess
import tempfile

from contextlib import contextmanager

from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)


TEMP_DIR = '/tmp/temp-ttl/ttl_1d'
ARCADIA_MOUNT_DIR = 'arcadia'
ARCADIA_STORE_DIR = 'store'
ARCADIA_MOUNT_DNA_DIR = 'arcadia/adv/frontend/services/dna'
ARCADIA_OBJECT_STORE_DIR = '/var/www/arc-object-store'
TOKENS = '/etc/direct-tokens/twilight/.env'
ST_API = 'https://st-api.yandex-team.ru'
ST_QUEUE = 'DIRECT'
ST_DNA_APP_COMPONENT = '38919'
ST_RELEASE_TICKET_TYPE = '12'
SANDBOX_API='https://sandbox.yandex-team.ru/api/v1.0'


def parse_arguments():
    parser = argparse.ArgumentParser(prog='dna-utils', formatter_class=argparse.RawTextHelpFormatter)
    subparsers = parser.add_subparsers(help=u'одна из команд из списка', metavar='COMMAND')

    parser_tests = subparsers.add_parser('tests', help=u'запуск интеграционных тестов DNA в сэндбоксе')
    parser_tests.add_argument( '--tests-branch', '-t', dest='tests_branch', required=True, type=str, help=u'ветка, из которой запускать тесты')
    parser_tests.add_argument('--beta-branch', '-b', dest='beta_branch', type=str, help=u'ветка, на сборке DNA (хэшсуммах) из которой запускать тесты; специальное значение "TS" – запуск на test-direct.yandex.ru')
    parser_tests.add_argument('--set', '-s', choices=['b2b', 'functional', 'frozen'], help=u'сэт тестов')
    parser_tests.add_argument('--grep', '-g', type=str, help=u'список тестов')
    parser_tests.add_argument('--beta-port', '-p', dest='beta_port', type=str, help=u'порт беты, на которой запускать тесты; специальное значение "TS" – запуск на test-direct.yandex.ru')
    parser_tests.add_argument('--features', '-f', type=str, help=u'список переопределяемых для запуска фич')
    parser_tests.set_defaults(func=run_tests)

    parser_tests = subparsers.add_parser('rerun-failed', help=u'перезапуск упавших интеграционных тестов DNA в сэндбоксе')
    parser_tests.add_argument( 'task_id', type=str, help=u'id таски sandbox c упавшими тестами')
    parser_tests.set_defaults(func=rerun_tests)

    parser_tests = subparsers.add_parser('get-latest-release-num', help=u'вывести номер текущего релиза DNA')
    parser_tests.set_defaults(func=get_latest_release_num)

    parser_tests = subparsers.add_parser('get-latest-release-package', help=u'вывести версию пакета в текущем релизе DNA')
    parser_tests.set_defaults(func=get_latest_release_package)

    parser_tests = subparsers.add_parser('get-latest-release-key', help=u'вывести тикет текущего релиза DNA')
    parser_tests.set_defaults(func=get_latest_release_key)

    parser_tests = subparsers.add_parser('update-omnipotent-betas', help=u'обновить единые беты для автотестов DNA')
    parser_tests.set_defaults(func=update_omnipotent_betas)

    args = parser.parse_args()
    return args


@contextmanager
def mktempdir(username):
    directory = tempfile.mkdtemp(prefix='dna-tests-%s-' % username, dir=TEMP_DIR)
    try:
        yield directory
    finally:
        shutil.rmtree(directory, ignore_errors=True)


def dotenv(path):
    with open(path, 'r') as fh:
        vars_dict = dict(
            tuple(item.strip('"\n') for item in line.split('='))
            for line in fh.readlines() if not line.startswith('#')
        )
    os.environ.update(vars_dict)


def capture_output(cmd, redirect_to=subprocess.PIPE):
    proc = subprocess.Popen(cmd, stdout=redirect_to, stderr=redirect_to, shell=False)
    lines = []
    can_read = hasattr(proc.stdout, 'readline')
    while can_read:
        line = proc.stdout.readline()
        if not line:
            break
        line = line.rstrip()
        lines.append(line)

    proc.wait()

    return lines, proc.returncode


def colored(r, g, b, text):
    return "\033[38;2;%s;%s;%sm%s \033[38;2;255;255;255m" % (r, g, b, text)


red = lambda text: colored(216, 63, 84, text)
green = lambda text: colored(34, 179, 92, text)
blue = lambda text: colored(79, 133, 214, text)
grey = gray = lambda text: colored(181, 189, 184, text)


@contextmanager
def checkout_dna(branch = 'trunk'):
    login = getpass.getuser()

    with mktempdir(login) as tmp_dir:
        os.chdir(tmp_dir)
        os.mkdir(ARCADIA_MOUNT_DIR)
        os.mkdir(ARCADIA_STORE_DIR)

        arc_dir = os.path.join(tmp_dir, ARCADIA_MOUNT_DIR)
        dna_dir = os.path.join(tmp_dir, ARCADIA_MOUNT_DNA_DIR)

        try:
            print('Mounting arcadia at {}'.format(arc_dir))
            subprocess.check_call(['arc', '--update'])
            subprocess.check_call([
                'arc', 'mount', '--vfs-version', '2', '--allow-other',
                '--mount', ARCADIA_MOUNT_DIR, '--store', ARCADIA_STORE_DIR,
                '--object-store', ARCADIA_OBJECT_STORE_DIR,
            ], env={'ARC_ALLOW_WRITE_TO_ALL': '1'})

            os.chdir(arc_dir)

            subprocess.check_call(['arc', 'fetch', branch])
            subprocess.check_call(['arc', 'checkout', branch])
            subprocess.check_call(['arc', 'pull', branch])

            os.chdir(dna_dir)

            yield
        finally:
            os.chdir(tmp_dir)
            print('Unmounting arcadia at {}'.format(arc_dir))
            subprocess.call(['arc', 'unmount', arc_dir])


def run_tests(args):
    with checkout_dna(args.tests_branch):
        subprocess.check_call(['npm', 'run', 'install:scripts-deps'])

        subprocess.check_call(['npm', 'run', 'hermione:sandbox', '--', '--tests-branch', args.tests_branch] \
                                + (['--set', args.set] if args.set else []) \
                                + (['--grep', args.grep] if args.grep else []) \
                                + (['--beta-branch', args.beta_branch] if args.beta_branch else []) \
                                + (['--beta-port', args.beta_port] if args.beta_port else []) \
                                + (['--features', json.dumps(args.features)] if args.features else []))


def rerun_tests(args):
    dotenv(TOKENS)
    # получение ветки для тестов из таски sandbox,
    # чтобы сразу выкачивать нужную ветку
    r = requests.get('%s/task/%s' % ( SANDBOX_API, args.task_id), \
        headers = {
            'Authorization': 'OAuth %s' % os.environ['SANDBOX_OAUTH_TOKEN'],
            'Content-Type': 'application/json; charset=utf-8'
        },
        verify = False
    )

    task = r.json()
    status = task['status']

    if status != 'SUCCESS' and status != 'FAILURE':
        return sys.exit(red(u'Таска sandbox должна быть завершена'))


    pattern = u'^DNA tests from (.+) on'
    match = re.match(pattern, task['description'])

    if not match:
        return sys.exit(red(u'В описании таски должно быть название ветки'))


    branch = match.groups()[0]

    with checkout_dna(branch):
        subprocess.check_call(['npm', 'run', 'install:scripts-deps'])
        subprocess.check_call(['npm', 'run', 'hermione:sandbox-failed', args.task_id])


def get_release_issue(branch = None):
    dotenv(TOKENS)

    filter = {
        'queue': ST_QUEUE,
        'components': ST_DNA_APP_COMPONENT,
        'type': ST_RELEASE_TICKET_TYPE
    }

    if (branch):
        filter['branch'] = branch

    r = requests.post('%s/v2/issues/_search' % ST_API, \
        headers = {
            'Authorization': 'OAuth %s' % os.environ['TWILIGHT_OAUTH_TOKEN'],
            'Content-Type': 'application/json'
        },
        params = {
            'perPage': 1
        },
        data = json.dumps({
            'filter': filter,
            'order': '-key'
        }),
        verify = False
    )
    [issue] = r.json()
    return issue


def get_latest_release_num(args):
    issue = get_release_issue()
    pattern = u'^Версия релиза: '

    line, = tuple(line for line in issue['description'].split('\n') if re.match(pattern, line))

    print re.sub(pattern, '', line)
    return issue


def get_latest_release_package(args):
    issue = get_release_issue()
    pattern = u'^Версия пакета с релизом: '

    line, = tuple(line for line in issue['description'].split('\n') if re.match(pattern, line))

    print re.sub(pattern, '', line)


def get_latest_release_key(args):
    print get_release_issue()['key']


def update_omnipotent_betas(args):
    with checkout_dna():
        node_cmd = '''
            const { getHostNumFromPort } = require('./.config/hermione/lib/betaHostHelpers');
            const ports = [12345, 12894, 13679, 13680, 14603, 14604];
            console.log(ports.map(p => [getHostNumFromPort(p), p]))
        '''

        betas_info = json.loads(subprocess.check_output(['node', '-e', node_cmd]))

    commands = (
        ['/usr/local/bin/direct-test-update', 'ppcdev{}'.format(ppcNum), 'direct-mk /var/www/beta.ppc.{} up'.format(port)]
        for ppcNum, port in betas_info
    )

    for command in commands:
        subprocess.check_call(command)


def main():
    args = parse_arguments()

    args.func(args)


if __name__ == '__main__':
    main()
