from saas.library.python.nanny_proto import Pod
from saas.library.python.nanny_proto import EndpointSet
from saas.library.python.ydb_filter_parser import Parser, Operator
from saas.library.python.nanny_rest.service import NannyServiceBase


def build_shardmap(service, dm_shardmap, shards_data=None):
    yp_shardmap = []
    gencfg_shardmap = []
    for shard in dm_shardmap:
        interval = shard['id'].split('-')
        shards_min = shard.get('$shards_min$', int(interval[0]))
        shards_max = shard.get('$shards_max$', int(interval[1]))
        gencfg_slots, yp_slots, nanny_shard_label = split_slots_by_type(shard['slots'])
        default_shard_label = '{}_{}_{}'.format(service.replace('-', '_'), shards_min, shards_max)
        shard_data = shards_data[
            (shards_min, shards_max)] if shards_data is not None else 'resourceless_shard_id={}'.format(
            default_shard_label)
        for yp_slot in yp_slots:
            shard_label = nanny_shard_label.get(yp_slot.service_id, default_shard_label)
            yp_slot.update_labels(shard=shard_label)
        shardmap_instance_info_yp = ['pod_label:shard={}'.format(sl) for sl in nanny_shard_label.values()]
        shardmap_instance_info_gencfg = [gencfg_slot_to_instance_info(s) for s in gencfg_slots]
        yp_shardmap.extend(['{} {}\n'.format(ii, shard_data) for ii in shardmap_instance_info_yp])
        gencfg_shardmap.extend(['{} {}\n'.format(ii, shard_data) for ii in shardmap_instance_info_gencfg])
    return yp_shardmap, gencfg_shardmap


def split_slots_by_type(slots):
    gencfg_slots, yp_slots, nanny_shard_label = [], [], {}
    for slot in slots:
        t_slot = slot['id'].split(':')[0]  # remove port
        if slot['is_sd']:
            endpoint_set = EndpointSet(*t_slot.split('@'))
            pod_filters = [f.value for f in Parser.parse(endpoint_set.pod_filter) if f.operator == Operator.equals and f.attribute == '/labels/shard']
            if len(pod_filters) != 1:
                raise RuntimeError('More than one pod filter in %s', endpoint_set)
            nanny_shard_label[endpoint_set.service_id] = pod_filters[0]
        else:
            try:
                yp_slots.append(Pod.from_fqdn(t_slot))
            except ValueError:
                # Not an yp_lite pod - probably gencfg
                gencfg_slots.append(slot)
    return gencfg_slots, yp_slots, nanny_shard_label


def gencfg_slot_to_instance_info(slot):
    return 'host_port:{}:{}'.format(slot['$real_host$'], slot['port'])


def match_rendered_shardmap(ctype, service, shards_data):
    from saas.library.python.deploy_manager_api.saas_service import SaasService
    from saas.library.python.nanny_rest import NannyServiceBase
    import sandbox.sdk2 as sdk2
    import requests
    service_from_saas = SaasService(ctype, service)
    yp_dm_shardmap, gencfg_dm_shardmap = build_shardmap(service, service_from_saas.slots_by_interval, shards_data)

    nanny_services = service_from_saas.nanny_services
    nanny_services_to_update = {}
    for nanny_service_name in nanny_services:
        nanny_service = NannyServiceBase(nanny_service_name)
        cur_sm = nanny_service.shard
        allocation_type = nanny_service.allocation_type.name
        if requests.Session().get("https://sandbox.yandex-team.ru/api/v1.0/task/{}".format(cur_sm.task_id)).status_code == 404:
            nanny_services_to_update[nanny_service_name] = True
            continue
        if cur_sm is None:
            nanny_services_to_update[nanny_service_name] = True
            continue
        shardmap_from_nanny = sdk2.Resource.find(task_id=cur_sm.task_id, type=cur_sm.resource_type).first()
        if shardmap_from_nanny is None:
            nanny_services_to_update[nanny_service_name] = True
            continue
        shardmap_from_dm = yp_dm_shardmap if allocation_type == 'yp_lite' else gencfg_dm_shardmap
        if len(shardmap_from_dm) <= 1:
            nanny_services_to_update[nanny_service_name] = False
            continue
        path_to_sh = sdk2.ResourceData(shardmap_from_nanny).path
        nanny_services_to_update[nanny_service_name] = sdk2.Task[cur_sm.task_id].Parameters.shards_data == '' and \
                ''.join(shardmap_from_dm) != path_to_sh.open().read()
    return nanny_services_to_update


def parse_proto_data(proto_data):
    from google.protobuf import text_format
    from saas.protos import shards_pb2
    return text_format.Parse(proto_data, shards_pb2.TShards())


def build_shards_data(yt_cluster, shards_data, yt_secret_id, yt_secret_key):
    import logging
    import yt.wrapper as yt
    import sandbox.sdk2 as sdk2
    result = {}
    logging.info('YT CLUSTER: %s', yt_cluster)
    logging.info('YT PATH: %s', shards_data)
    yt.config.set_proxy(yt_cluster)
    robot_saas_secret = sdk2.yav.Secret(yt_secret_id)
    yt.config.config['token'] = robot_saas_secret.data()[yt_secret_key]
    shards_data_msg = yt.read_file(shards_data).read()
    shards_data = parse_proto_data(shards_data_msg)
    for shard in shards_data.Shard:
        if not shard.Torrent:
            raise RuntimeError('No torrent for shard {}-{}'.format(shard.ShardMin, shard.ShardMax))
        result[(shard.ShardMin, shard.ShardMax)] = shard.Torrent
    return result


def collect_nanny_service_recipes(service_name):
    nanny_service = NannyServiceBase(service_name)
    nanny_info = nanny_service.info_attrs['recipes']
    activating_recipes = set([el['id'] for el in nanny_info['content']])
    preparing_recipes = nanny_info.get('prepare_recipes', [])
    return activating_recipes, preparing_recipes
