# -*- coding: utf-8 -*-

import logging

import duty
import random
import saas.tools.ssm.modules.startrek_api as startrek_api
import saas.tools.ssm.modules.abc_api as abc_api
import saas.tools.devops.lib23.service_topology_tools as stt

from flask import current_app

startrek_client = startrek_api.SaaSStartrekWorkflow()
abc_client = abc_api.ABCApi()


def get_quota_resp(abc_id):
    """
    Get users with role quotas_management. If does not exist check users with role services_management and return first.
    :param abc_id: type str
    :return:
    """
    quota_managers = abc_client.get_logins_by_role(abc_id, 'quotas_management')
    if not quota_managers:
        quota_managers = abc_client.get_logins_by_role(abc_id, 'services_management')
    return quota_managers[0] if len(quota_managers) > 0 else ''


def saas_duty():
    current_duty = duty.get_current_duty()
    if current_duty:
        if type(current_duty) is list:
            random.shuffle(current_duty)
            return current_duty
        else:
            return [current_duty]
    return []


def make_followers_list(data, user=None):
    followers = []
    if 'sla_info' in data and data['sla_info'].get('owners'):
        followers.extend(data['sla_info']['owners'])
    if 'owners_list' in data:
        followers.extend(data['owners_list'])
    if user and user not in followers:
        followers.append(user)
    followers.extend(saas_duty())
    return followers


def startrek_create_service_ticket(data, user=None):
    """
    Create Startrek service issue using specified data
    :param data: type dict
    :param user: type None or type str
    :return: type str
    """
    logging.info('Creating SaaS service ticket')

    followers = make_followers_list(data, user=user)
    issue_tags = ['new_service', 'service:%s' % (data['service_name'])]

    other_data = prepare_issue_data(data)

    # Additional issue tags
    if other_data.get('delivery_type'):
        other_data['delivery_type'] = data['delivery_info']['delivery_type_value']
        if 'ferryman' in data['delivery_info']['delivery_type']:
            issue_tags.append('ferryman')
        if 'logbroker' in data['delivery_info']['delivery_type']:
            issue_tags.append('logbroker')
        if data['delivery_info']['delivery_type'] == 'snapshot':
            issue_tags.append('snapshot')

    duty_list = saas_duty()
    duty = duty_list[0] if len(duty_list) > 0 else ''
    logging.debug('Current on duty person: %s', duty)
    ticket = startrek_client.new_service_request(data['service_name'], data['service_ctype'], data['service_type'],
                                                 data['instances_count']/data['replicas_per_dc'], data['comment'],
                                                 other_data=other_data, tags=issue_tags, followers=followers)
    if duty:
        startrek_client.change_assignee(ticket, duty)
    if user:
        startrek_client.set_issue_author(ticket, user)
    startrek_client.change_tags(ticket, issue_tags)
    return ticket


def startrek_create_namespace_ticket(data, user=None):
    """
    Create Startrek namespace issue using specified data
    :param data: type dict
    :param user: type None or type str
    :return: type str
    """
    logging.info('Creating SaaS namespace ticket')

    followers = make_followers_list(data, user=user)
    issue_tags = ['new_namespace', 'namespace_name:%s' % (data['namespace_name'])]

    data = prepare_issue_data(data)

    duty_list = saas_duty()
    duty = duty_list[0] if len(duty_list) > 0 else ''
    logging.debug('Current on duty person: %s', duty)
    ticket = startrek_client.new_namespace_request(data['namespace_name'], data['ferryman_service'], data['ferryman_ctype'], data['comment'],
                                                   owners_list=data.get('owners_list'), namespace_size=data.get('namespace_size'),
                                                   namespace_doccount=data.get('namespace_doccount'), tags=issue_tags, followers=followers)
    if duty:
        startrek_client.change_assignee(ticket, duty)
    if user:
        startrek_client.set_issue_author(ticket, user)
    startrek_client.change_tags(ticket, issue_tags)
    return ticket


def startrek_create_sec_ticket(data, user=None):
    """
    Create Startrek security issue using specified data
    :param data: type dict
    :param user: type None or type str
    :return: type str
    """
    logging.info('Creating SaaS security ticket')

    startrek_client = startrek_api.SaaSStartrekWorkflow(queue='SAASSEC')
    followers = make_followers_list(data, user=user)
    # Add ezaitov@ tosecutiry tickets
    followers.append('ezaitov')
    issue_tags = ['tvm', 'service:%s' % (data['service_name'])]
    ticket = startrek_client.new_security_request(data['service_name'], data['service_ctype'], data['service_type'],
                                                  tags=issue_tags, followers=followers)
    if user:
        startrek_client.change_assignee(ticket, user)
    return ticket


def startrek_create_perf_ticket(data, user=None):
    """
    Create Startrek perftest issue using specified data
    :param data: type dict
    :param user: type None or type str
    :return: type str
    """
    logging.info('Creating SaaS performance ticket')

    followers = make_followers_list(data, user=user)
    issue_tags = ['tvm', 'service:%s' % (data['service_name'])]
    startrek_client = startrek_api.SaaSStartrekWorkflow(queue='SAASLOADTEST')
    ticket = startrek_client.new_perftest_request(data['service_name'], data['service_ctype'], data['service_type'],
                                                  tags=issue_tags, followers=followers)
    if user:
        startrek_client.change_assignee(ticket, user)
    startrek_client.change_tags(ticket, issue_tags)
    return ticket


def startrek_create_service_production_ticket(data, user=None):
    """
    Create Startrek production issue using specified data
    :param data: type dict
    :param user: type None or type str
    :return: type str
    """
    logging.info('Creating SaaS production ticket')

    followers = make_followers_list(data, user=user)
    issue_tags = ['production_prepare', 'service:%s' % (data['service_name'])]
    ticket = startrek_client.new_service_production_request(data['service_name'], data['service_ctype'], data['service_type'],
                                                            tags=issue_tags, followers=followers)
    if user:
        startrek_client.change_assignee(ticket, user)
    startrek_client.change_tags(ticket, issue_tags)
    startrek_client.block_issue(ticket)

    return ticket


def startrek_quota_report(ticket_num, quotas_data, request_data):
    """
    Calculate required resources anc check available resources of quota service and place it into startrek issue.
    :param ticket_num: type str
    :param quotas_data: type dict
    :param request_data: type dict
    :return:
    """
    required_hdd = stt.calculate_workdir_volume_size() + stt.calculate_root_volume_size() + \
                   stt.calculate_cores_volume_size(int(request_data['req_memory']) * 2 ** 30) + \
                   stt.calculate_logs_volume_size(int(request_data['sla_info'].get('search_rps', 10)), request_data['replicas_per_dc'] * 3)
    required_ssd = stt.calculate_data_volume_size(int(request_data['sla_info'].get('total_index_size_bytes', 0)),
                                                  request_data['instances_count'] / request_data.get('replicas_per_dc', 1))
    required_resources = {'CPU': request_data['req_cpu'] * request_data['instances_count'],
                          'RAM': request_data['req_memory'] * request_data['instances_count'],
                          'HDD': required_hdd * request_data['instances_count'],
                          'SSD': required_ssd * request_data['instances_count']}
    qs = abc_client.get_hr_service_name(request_data['sla_info']['abc_quota_service'], lang='en')[0]

    # Add quota responsible to ticket
    startrek_client.add_to_followers(ticket_num, get_quota_resp(request_data['sla_info']['abc_quota_service']))

    logging.debug(quotas_data)

    for quota in quotas_data:
        if qs == quota and 'resources_avail' in quotas_data[quota]:
            qs_r = quotas_data[quota].get('resources_avail')
            logging.info(qs_r)
            comment_data = """Остаток квоты сервиса ((https://abc.yandex-team.ru/services/{qs}/ {qs})) на текущий момент:
#|
|| **SAS** | **MAN** | **VLA** ||
|| CPU: {cpu_sas} | CPU: {cpu_man} | CPU: {cpu_vla} ||
|| RAM: {ram_sas} | RAM: {ram_man} | RAM: {ram_vla} ||
|| HDD: {hdd_sas} | HDD: {hdd_man} | HDD: {hdd_vla} ||
|| SSD: {ssd_sas} | SSD: {ssd_man} | SSD: {ssd_vla} ||
|#""".format(cpu_sas=qs_r['SAS']['CPU'], cpu_man=qs_r['MAN']['CPU'], cpu_vla=qs_r['VLA']['CPU'],
             ram_sas=qs_r['SAS']['RAM'], ram_man=qs_r['MAN']['RAM'], ram_vla=qs_r['VLA']['RAM'],
             hdd_sas=qs_r['SAS']['HDD'], hdd_man=qs_r['MAN']['HDD'], hdd_vla=qs_r['VLA']['HDD'],
             ssd_sas=qs_r['SAS']['SSD'], ssd_man=qs_r['MAN']['SSD'], ssd_vla=qs_r['VLA']['SSD'],
             qs=qs)
            break
    else:
        comment_data = """Не найдено квота-сервиса ((https://abc.yandex-team.ru/services/{qs}/ {qs})).
Внимание дежурному, требуется ручное вмешательство.""".format(qs=qs)
    comment_data += """Требуется ресурсов для создания сервиса:
#|
|| **SAS** | **MAN** | **VLA** ||
|| CPU: {cpu} | CPU: {cpu} | CPU: {cpu} ||
|| RAM: {ram} | RAM: {ram} | RAM: {ram} ||
|| HDD: {hdd} | HDD: {hdd} | HDD: {hdd} ||
|| SSD: {ssd} | SSD: {ssd} | SSD: {ssd} ||
|#

Полная информация о квотах проектов доступна по адресу: https://{host}/quota_used
""".format(cpu=str(required_resources['CPU']), ram=str(required_resources['RAM']) + ' Gb', hdd=str(required_resources['HDD']) + ' Gb',
           ssd=str(required_resources['SSD']) + ' Gb', host=current_app.config.get('BASE_HOST'))
    startrek_client.add_comment(ticket_num, comment_data)


def startrek_approve_comment(ticket_num, data, rtype=None):
    """
    Check request type and instances count and write comment
    :param ticket_num: type str
    :param data: type dict
    :param rtype: type str
    """
    current_duty = duty.get_current_duty()
    if rtype == 'production':
        startrek_client.add_comment(ticket_num, 'Для создания сервиса требуется {} инстанса(ов) на локацию. '
                                                'Требуется подтверждение. Подтвердить заявку можно по адресу '
                                                'https://ssm.n.yandex-team.ru/requests'.format(data['instances_count']),
                                    summonees=current_duty)
    elif rtype in ['prestable', 'testing'] and data['instances_count'] <= 10:
        startrek_client.add_comment(ticket_num, 'Для создания {} сервиса требуется {} инстанса(ов). '
                                                'Подтверждения не требуется'.format(rtype, data['instances_count']))
    elif rtype == 'namespace' and int(data['namespace_size']) <= 2**30:
        startrek_client.add_comment(ticket_num, 'Для создания неймспейса требуется <= 1Gb пространства. '
                                                'Подтверждения не требуется')
    else:
        startrek_client.add_comment(ticket_num, 'Для выполнения заявки требуется подтверждение. Подтвердить заявку можно по адресу '
                                                'https://ssm.n.yandex-team.ru/requests',
                                    summonees=current_duty)


def prepare_issue_data(data):
    """
    Collect information for creating Startrek issue
    :param data: type dict
    :return: type dict
    """
    # Collect data fields for issue creation
    issue_data = data.copy()
    if 'sla_info' in data:
        issue_data.update(data['sla_info'])
    if 'delivery_info' in data:
        issue_data.update(data['delivery_info'])

    # Convert index size and max docs parameter to human readable value
    if issue_data.get('total_index_size_bytes'):
        issue_data['total_index_size_bytes'] /= 1073741824.0
    if issue_data.get('maxdocs'):
        issue_data['maxdocs'] /= 1000000.0
    if issue_data.get('namespace_doccount'):
        issue_data['namespace_doccount'] /= 1000000.0
    if issue_data.get('namespace_size'):
        issue_data['namespace_size'] /= 1073741824.0
    logging.debug(issue_data)
    return issue_data
