import fileinput
import sys
import requests
import json
import typing
import pprint as pp
from datetime import datetime

import yt.wrapper as yt
from yp.client import YpClient

from balancer.production.x.upstreams_info.tokens import YT_TOKEN, \
    YP_TOKEN, NANNY_TOKEN


def get_backend_type(backend_name):
    if backend_name[0].islower():
        return "yp"
    else:
        return "gencfg"


def get_backend_dc(backend_type, backend_name):
    if backend_type == "yp":
        dc = backend_name[-3:]
        return dc
    elif backend_type == "gencfg":
        dc = backend_name[:3].lower()
        return dc
    else:
        raise RuntimeError("Bad backend type in ABC func")


class BackendInfo:
    def __init__(self, line):
        before_field, _, _, upstream_and_backend, \
            self.regexp, _, _ = line.split('"')
        self.upstream_name, self.name, _ = upstream_and_backend.split('::')
        self.type = get_backend_type(self.name)
        self.dc = get_backend_dc(self.type, self.name)
        if self.type == "gencfg":
            self.name = self.name.split('(')[0]
        self.config_name = before_field.split(':')[0]

    def __str__(self):
        result_repr = ''
        result_repr += 'Upstream: ' + self.upstream_name + '\n'
        result_repr += 'Regexp: "' + self.regexp + '"\n'
        result_repr += '\tBackend type: ' + self.type + '\n'
        result_repr += '\tBackend:      ' + self.name + '\n'
        result_repr += '\tBackend DC:   ' + self.dc + '\n'
        result_repr += '\tConfig name:  ' + self.config_name + '\n'

        return result_repr


class GencfgClient:
    def __init__(self, token=NANNY_TOKEN):
        self.token = token
        self.host = 'https://nanny.yandex-team.ru'

    def get_nanny_service_id_for_backend(self, backend_info):
        request = self.host + '/api/repo/GetServicesForGencfgGroup/'
        payload = {'groupName': backend_info.name}
        headers = {'authorization': 'OAuth {}'.format(NANNY_TOKEN)}
        text_result = requests.post(
            request,
            data=json.dumps(payload),
            headers=headers
        )
        parsed_result = json.loads(text_result.text)
        pp.pprint(parsed_result)

        return parsed_result['serviceRefs'][0]['id']


class NannyClient:
    def __init__(self, token=NANNY_TOKEN):
        self.token = token
        self.host = 'https://nanny.yandex-team.ru'

    def get_abc_group_id(self, service_id):
        request = self.host + '/v2/services/{}/info_attrs/'.format(service_id)
        headers = {'authorization': 'OAuth {}'.format(self.token)}
        text_result = requests.get(request, headers=headers)
        parsed_result = json.loads(text_result.text)

        return parsed_result['content']['abc_group']


class AbcResolver:
    def __init__(self):
        self.yp_client = {
            'vla': YpClient("vla", config={"token": YP_TOKEN}),
            'sas': YpClient("sas", config={"token": YP_TOKEN}),
            'man': YpClient("man", config={"token": YP_TOKEN}),
        }
        self.gencfg_client = GencfgClient()
        self.nanny_client = NannyClient(NANNY_TOKEN)

    def _get_abc_for_yp_backend(self, backend_info):
        result = self.yp_client[backend_info.dc].get_object(
            "endpoint_set", backend_info.name,
            selectors=["/labels"],
        )
        return result[0]['nanny']['nanny_service_id']

    def _get_abc_for_gencfg_backend(self, backend_info):
        result = self.gencfg_client.get_nanny_service_id_for_backend(
            backend_info
        )
        return result

    def _get_abc_for_nanny_service(self, service_id):
        abc_host = 'https://abc.yandex-team.ru'
        abc_group_id = self.nanny_client.get_abc_group_id(service_id)
        return (abc_host + '/services/{}/'.format(abc_group_id), abc_group_id)

    def get_abc_for_backend(self, backend_info):
        nanny_service_id = None
        if backend_info.type == "yp":
            nanny_service_id = self._get_abc_for_yp_backend(backend_info)
        elif backend_info.type == "gencfg":
            nanny_service_id = self._get_abc_for_gencfg_backend(backend_info)
        else:
            raise RuntimeError("Bad backend type in ABC func")

        return self._get_abc_for_nanny_service(nanny_service_id)


class ResultInfo:
    def __init__(self, abc_link, abc_id, backend_info):
        self.abc_link = abc_link
        self.abc_id = abc_id
        self.regexp = backend_info.regexp
        self.backend_info = backend_info

    def __str__(self):
        result_repr = str(self.backend_info)
        result_repr += '\tAbc link:     ' + self.abc_link + '\n'
        result_repr += '\tAbc id:       ' + str(self.abc_id) + '\n'
        return result_repr


def handle_line(line, abc_resolver):
    backend_info = BackendInfo(line)

    abc_link, abc_id = abc_resolver.get_abc_for_backend(backend_info)

    return ResultInfo(abc_link, abc_id, backend_info)


@yt.yt_dataclass
class UpstreamInfoRow:
    service_provider_id: str
    resource_id: typing.Dict[str, str]
    resource_type: str
    environment: str
    abc_id: int
    config: str
    upstream: str
    regexp: str
    backend_group: str
    abc_link: str


def get_resource_id(RESOURCE_TYPE, result):
    return {
        RESOURCE_TYPE: '{}:{}'.format(
            result.backend_info.config_name,
            result.backend_info.upstream_name,
        )
    }


def create_results_table(results):
    client = yt.YtClient(proxy='hahn', token=YT_TOKEN)
    table = '//tmp/upstreams_info-{}'.format(
            datetime.now().strftime('%Y-%m-%d_%H:%M:%S')
    )
    SERVICE_PROVIDER_ID = 'L7'
    RESOURCE_TYPE = 'upstream'

    table_raws = []
    for result in results:
        resource_id = get_resource_id(RESOURCE_TYPE, result)
        table_raws.append(
            UpstreamInfoRow(
                service_provider_id=SERVICE_PROVIDER_ID,
                resource_id=resource_id,
                resource_type=RESOURCE_TYPE,
                environment='PRODUCTION',
                abc_id=result.abc_id,
                config=result.backend_info.config_name,
                upstream=result.backend_info.upstream_name,
                regexp=result.backend_info.regexp,
                backend_group=result.backend_info.name,
                abc_link=result.abc_link,
            )
        )

    client.write_table_structured(
        table,
        UpstreamInfoRow,
        table_raws,
    )


def _main():
    progress = 0
    yp_count = 0
    gencfg_count = 0
    abc_resolver = AbcResolver()
    results = []

    for line in fileinput.input():
        progress += 1
        print(progress, file=sys.stderr)

        result = handle_line(line, abc_resolver)
        results.append(result)
        print(result)

        if result.backend_info.type == 'yp':
            yp_count += 1
        else:
            gencfg_count += 1

    print("YP count:     " + str(yp_count), file=sys.stderr)
    print("Gencfg count: " + str(gencfg_count), file=sys.stderr)

    create_results_table(results)


if __name__ == "__main__":
    _main()
