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

import os
import logging
import argparse
import time
import json

import search.tools.devops.libs.utils as u

from saas.tools.devops.lib.saas_recluster import get_current_topology
from saas.tools.devops.lib.saas_recluster import recluster_nanny_service

from sandbox.common.rest import Client as SandboxClient
from sandbox.common.proxy import OAuth


def execute_sandbox_task(
        task_type,
        sandbox_token=os.environ.get("OAUTH_SANDBOX", None),
        user=os.environ.get("USER", None),
        custom_fields=[],
        wait_for_success=True,
        description=None,
        ):

    sandbox = SandboxClient(auth=OAuth(sandbox_token))
    task_id = sandbox.task({'type': task_type})['id']
    logging.info('Sandbox task {} spawned'.format(task_id))

    sandbox.task[task_id] = {
        'owner': user,
        'description': description,
        'custom_fields': custom_fields,
        'priority': {'class': 'USER', 'subclass': 'NORMAL'}
    }

    resp = sandbox.batch.tasks.start.update(task_id)[0]
    logging.info('Running sandbox task {} : {}'.format(task_id, resp))

    if wait_for_success:
        task_status = sandbox.task[task_id].read()['status']
        sleep_step = 10.0
        while task_status != 'SUCCESS':
            if task_status in ('FAILURE', 'EXCEPTION'):
                logging.error('Sandbox task {} status : {}'.format(task_id, task_status))
                sleep_step = 60.0
            else:
                logging.info('Sandbox task {} status : {}'.format(task_id, task_status))
                sleep_step *= 1.1
            time.sleep(int(sleep_step))
            task_status = sandbox.task[task_id].read()['status']
        logging.info('Sandbox task {} status : {}'.format(task_id, task_status))


def test_sandbox_tasking():

    logging.info("Testing sandbox tasking routines")

    task_type = "REMOTE_COPY_RESOURCE"
    custom_fields = [
        {'name': "resource_type", 'value': "INSTANCECTL"},
        {'name': "created_resource_name", 'value': "RESOURCE"},
        {'name': "remote_file_name", 'value': "rbtorrent:4efa6ab4dbdc57fcda482d2dda82bfa4f9f64dcc"},
        {'name': "remote_file_protocol", 'value': "skynet"},
        ]
    description = 'Test ref#SAAS-3530'

    execute_sandbox_task(task_type, custom_fields=custom_fields, description=description)


def do_backup(
        service,
        sandbox_token=os.environ.get("SANDBOX_TOKEN", None),
        user=os.environ.get("USER", None),
        shard_range='0-65533',
        backup_ttl='7',
        max_download_speed='300mbs',
        delay_threshold='4',
        do=False,
        ):

    task_type = 'DETACH_SERVICE_INDEX'
    description = 'Pre-recluster backup of {}'.format(service)
    custom_fields = [
        {'name': 'service_name', 'value': service},
        {'name': "shard_range", 'value': "0-65533"},
        {'name': "resource_ttl", 'value': "7"},
        {'name': "max_download_speed", 'value': "300mbps"},
        {'name': "delay_threshold", 'value': "4"},
        {'name': "save_all_indexes", 'value': 'true'},
    ]

    if do:
        execute_sandbox_task(task_type, custom_fields=custom_fields, description=description)
    else:
        logging.info("NOT performing backup with params {}".format({'task_type': task_type, 'custom_fields': custom_fields, 'description': description}))


def parse_cmd_args():

    description = '''
Recluster SaaS refresh services

Known bugs and limitations : this script will update revisions of all GENCFG groups to given value.
It cannot set different revisions to different groups and will not work if you have one group with multiple active revisions.

You need to have defined OAuth tokens for nanny and sandbox in your ENV, just like this:
    export OAUTH_NANNY='{Get your token here : https://nanny.yandex-team.ru/ui/#/oauth/}'
    export OAUTH_SANDBOX='{Get your token here : https://sandbox.yandex-team.ru/oauth/token#}'

'''

    parser = argparse.ArgumentParser(description=description)

    parser.add_argument(
        '-t', '--new-topology',
        type=str,
        help='Target topology to recluster to'
    )

    parser.add_argument(
        '-l', '--list-topology',
        default=False,
        action='store_true',
        help='Print actual service topology and exit'
    )

    parser.add_argument(
        '-s', '--service',
        type=str,
        default='saas_refresh_3day_devrecluster_base_multilang_i024',
        help='Service to recluster'
    )

    parser.add_argument(
        '-d', '--debug',
        default=False,
        action='store_true',
        help='Dump actual debug info'
    )

    parser.add_argument(
        '-b', '--do-backup',
        default=False,
        action='store_true',
        help="Do DETACH_SERVICE_INDEX task before reclustering"
    )

    parser.add_argument(
        '--skip-multi-topology-stage',
        default=False,
        action='store_true',
        help="Activate new topology without intermediate phases."
    )

    parser.add_argument(
        '--no-nanny-activation',
        default=False,
        action='store_true',
        help="Skip nanny service activaions. Just commit."
    )

    parser.add_argument(
        '--no-old-snapshot-check',
        default=False,
        action='store_true',
        help="Do not check if current snapshot is active (to avoid collisions with Marty)."
    )

    return parser.parse_args()


def main():

    args = parse_cmd_args()
    if args.debug:
        u.logger_setup(verbose_level=2)
        logging.info("Config : {}".format(str(args)))
    else:
        u.logger_setup(verbose_level=1)

    service = args.service

    if args.list_topology:
        print(json.dumps(get_current_topology(service), indent=2))
        return 0

    if not args.new_topology:
        logging.critical("Either --new-topology or --list-topology is required")
        return 255

    if args.do_backup:
        do_backup(
            service,
            do=True,
        )

    two_phase = not args.skip_multi_topology_stage
    dry_run = args.no_nanny_activation
    new_topology = args.new_topology
    old_snapshot_check = not args.no_old_snapshot_check

    recluster_nanny_service(service, new_topology, two_phase, dry_run, old_snapshot_check)


if __name__ == "__main__":

    main()
