import time
import logging
import click
import sys
import random

from infra.yasm.yasmapi import GolovanRequest

from saas.tools.devops.lib23.saas_entity import saas_service_iterator
from saas.tools.devops.lib23.nanny_helpers import NannyReleaseRunner


def saas_prj(saas_ctype, saas_service):
    return '-'.join([saas_ctype, saas_service]).replace('_', '-').replace('stable', 'saas', 1)


def get_service_usage_rate(saas_ctype, saas_service, geo=None):

    ALL_GEO = 'sas,man,vla'
    if geo is None:
        geo = ALL_GEO

    proxy_2xx_signal = \
        "itype=searchproxy;geo={}:saas_unistat-search-{}-{}-2xx_dmmm".format(
            geo,
            saas_ctype,
            saas_service
        )

    backend_instance_counter_signal = \
        "itype=rtyserver;ctype=prod;prj={};geo={}:counter-instance_tmmv".format(
            saas_prj(saas_ctype, saas_service),
            geo
        )

    backend_rps_signal = \
        "itype=rtyserver;ctype=prod;prj={};geo={}:hcount(saas_unistat-search-times-{}-{}-full_dhhh, 0, inf)".format(
            saas_prj(saas_ctype, saas_service),
            geo,
            saas_ctype,
            saas_service
        )

    host = "ASEARCH"

    periods = [5 * 60, 60 * 60]  # 5 minutes periods for daily and 1h periods for monthly
    period_counts = [24 * 60 * 60 / 300, 24 * 30]

    rps_history = {}
    instance_counter_history = {}
    backend_rps_history = {}

    for period, periods_count in zip(periods, period_counts):
        et = time.time() - period * 3
        st = et - period * periods_count

        signals = [proxy_2xx_signal, backend_instance_counter_signal, backend_rps_signal]
        for timestamp, values in GolovanRequest(host, period, st, et, signals):

            rps = values[proxy_2xx_signal] / float(period)
            backend_rps = values[backend_rps_signal] / float(period)

            rps_history[timestamp] = rps
            backend_rps_history[timestamp] = backend_rps
            instance_counter_history[timestamp] = values[backend_instance_counter_signal]

    return rps_history, backend_rps_history, instance_counter_history


# print all_inactive_services
@click.command('process_release')
@click.option(
    'sandbox_task_id',
    '--sandbox-task',
    help=(
        'Sandbox task id'
    ),
    required=False
)
@click.option(
    'release_type',
    '--release-type',
    required=False
)
@click.option(
    'nanny_release_id',
    '--nanny-release',
    required=False
)
@click.option(
    'detect_offline_services',
    '--detect-offline-services',
    required=False
)
@click.option(
    'concurrent_deployments',
    '--concurrent-deployments',
    required=False
)
@click.option(
    'deployments_limit',
    '--deployments-limit',
    required=False
)
@click.option(
    'sample_size',
    '--sample-size',
    required=False
)
def process_release(sandbox_task_id, release_type, nanny_release_id, detect_offline_services, concurrent_deployments, deployments_limit, sample_size):

    print(sandbox_task_id, release_type, nanny_release_id, detect_offline_services, concurrent_deployments, deployments_limit, sample_size)
    # sandbox_task_id = '519820620'
    release_type = 'stable'
    # nanny_release_id = None
    detect_offline_services = False

    deploy_queue = []

    if detect_offline_services:
        logging.error('Looking for offline services')
        for ss in saas_service_iterator():
            try:
                (rps_history, backend_rps_history, instance_counter_history) = get_service_usage_rate(ss.ctype, ss.name)
                print("{}/{} usage rate : {}, {}".format(ss.ctype, ss.name, max(rps_history.values()), max(backend_rps_history.values())))

                if max(rps_history.values()) == 0 and max(backend_rps_history.values()) == 0:
                    deploy_queue.extend(ss.nanny_services)
            except:
                logging.exception("Can't obtain Golovan data for %s/%s", ss.ctype, ss.name)

        logging.warn("Found %s services without traffic, will deploy : %s", len(deploy_queue), [ss.name for ss in deploy_queue])
    else:
        logging.error('Adding all services to deploy queue')
        saas_services_to_deploy = list(saas_service_iterator())
        logging.error('Found %s SaaS services', len(saas_services_to_deploy))

        print(sample_size)
        if sample_size:
            random.shuffle(saas_services_to_deploy)
            saas_services_to_deploy = saas_services_to_deploy[:int(sample_size)]
        print(len(saas_services_to_deploy), saas_services_to_deploy)

        try:
            saas_services_to_deploy.sort(key=lambda s: s.get_release_branch())
            logging.error('Sorted')
        except:
            logging.exception("Not sorted")

        if deployments_limit:
            saas_services_to_deploy = saas_services_to_deploy[:deployments_limit]

        for ss in saas_services_to_deploy:
            logging.error("Add service %s: %s", ss.name, ss.nanny_services)
            deploy_queue.extend(ss.nanny_services)

    logging.error([ns.name for ns in deploy_queue])

    service_to_ticket_mapping = {}
    for sandbox_task in [sandbox_task_id]:
        rr = NannyReleaseRunner(sandbox_task_id=sandbox_task, release_type=release_type, nanny_release_id=nanny_release_id)
        logging.error(rr)
        for ticket in rr.tickets:
            service_to_ticket_mapping[ticket.spec.service_deployment.service_id] = ticket

        for ns in deploy_queue:
            if ns.name in service_to_ticket_mapping:
                ticket = service_to_ticket_mapping[ns.name]
                if ticket.status.status in [0, 8, 9]:  # IN_QUEUE, COMMITTED, PREPARED
                    logging.error("Activating %s", ticket.spec.service_deployment.service_id)
                    rr.activate_ticket(ticket)
                    time.sleep(120)
                else:
                    logging.debug(ticket.status.status)


if __name__ == '__main__':
    if not process_release():
        sys.exit(1)
