# coding: utf-8

from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals

import re
import six

from infra.nanny.yp_lite_api.proto import pod_sets_api_pb2
from infra.nanny.yp_lite_api.py_stubs.pod_sets_api_stub import YpLiteUIPodSetsServiceStub

from saas.library.python.nanny_proto.rpc_client_base import NannyRpcClientBase


class Pod(NannyRpcClientBase):
    _identity = ['cluster', 'pod_id']
    _RPC_URL = 'https://yp-lite-ui.nanny.yandex-team.ru/api/yplite/pod-sets/'
    _API_STUB = YpLiteUIPodSetsServiceStub
    _POD_FQDN_REGEXP = re.compile(r'\A(?P<pod_id>[a-z0-9-]+)\.(?P<cluster>[a-z-]+)\.yp-c\.yandex\.net\Z')
    _YP_HOSTNAME_SUFFIX = 'yp-c.yandex.net'
    system_labels = ('nanny_version', 'nanny_service_id')

    @classmethod
    def _patch_dict(cls, d, update):
        d.update(update)
        return {k: v for k, v in six.iteritems(d) if v is not None and k not in cls.system_labels}

    def __init__(self, cluster, pod_id, proto_msg=None):
        super(Pod, self).__init__()
        self._cluster = cluster.upper()
        self._id = pod_id
        self._proto_msg = proto_msg

    def __repr__(self):
        return 'Pod({}, {})'.format(self._cluster, self._id)

    @classmethod
    def from_fqdn(cls, fqdn):
        normal_fqdn = fqdn.lower()
        match = cls._POD_FQDN_REGEXP.match(normal_fqdn)
        if not match:
            raise ValueError('{} is not valid yp lite fqdn'.format(normal_fqdn))
        cluster = match.group('cluster').upper().replace('-', '_')
        return cls(cluster, match.group('pod_id'))

    @classmethod
    def list(cls, cluster, service_id, limit=500, offset=0):
        cluster = cluster.upper()
        cls._init_client()
        req = pod_sets_api_pb2.ListPodsRequest(service_id=service_id, cluster=cluster, offset=offset, limit=limit)
        res = cls._CLIENT.list_pods(req)  # type: pod_sets_api_pb2.ListPodsResponse
        return [cls(cluster, pod.meta.id, pod) for pod in res.pods]

    @property
    def cluster(self):
        return self._cluster

    @property
    def id(self):
        return self._id

    @property
    def hostname(self):
        return '.'.join([self._id, self._cluster, self._YP_HOSTNAME_SUFFIX]).lower()

    @property
    def proto_msg(self):
        if self._proto_msg is None:
            req = pod_sets_api_pb2.GetPodRequest(pod_id=self._id, cluster=self._cluster)
            self._proto_msg = self._CLIENT.get_pod(req).pod
        return self._proto_msg

    @property
    def labels(self):
        return {att.key: att.value.decode() for att in self.proto_msg.labels.attributes}

    @labels.setter
    def labels(self, value):
        value['nanny_service_id'] = self.service_id
        req = pod_sets_api_pb2.UpdatePodRequest(pod_id=self._id, version=self.version, labels=value, cluster=self._cluster)
        self._CLIENT.update_pod(req)
        self._proto_msg = self._CLIENT.get_pod(pod_sets_api_pb2.GetPodRequest(pod_id=self._id, cluster=self._cluster)).pod

    def update_labels(self, **kwargs):
        self.labels = self._patch_dict(self.labels, kwargs)

    @property
    def annotations(self):
        return {att.key: att.value.decode() for att in self.proto_msg.annotations.attributes}

    @annotations.setter
    def annotations(self, value):
        req = pod_sets_api_pb2.UpdatePodRequest(pod_id=self._id, version=self.version, annotations=value, cluster=self._cluster)
        self._CLIENT.update_pod(req)
        self._proto_msg = self._CLIENT.get_pod(pod_sets_api_pb2.GetPodRequest(pod_id=self._id, cluster=self._cluster)).pod

    def update_annotations(self, **kwargs):
        self.annotations = self._patch_dict(self.annotations, kwargs)

    @property
    def service_id(self):
        return self.labels['nanny_service_id']

    @property
    def version(self):
        return self.labels['nanny_version']

    def update(self, labels=None, annotations=None):
        if not (labels or annotations):
            self.LOGGER.warning('Update for %s without labels or annotation')
            return

        new_labels = self._patch_dict(self.labels, labels) if labels is not None else self.labels
        new_labels['nanny_service_id'] = self.service_id
        new_annotations = self._patch_dict(self.annotations, annotations) if annotations is not None else self.annotations

        req = pod_sets_api_pb2.UpdatePodRequest(pod_id=self._id, version=self.version, labels=new_labels, annotations=new_annotations, cluster=self._cluster)
        self._CLIENT.update_pod(req)
        self._proto_msg = self._CLIENT.get_pod(pod_sets_api_pb2.GetPodRequest(pod_id=self._id, cluster=self._cluster)).pod
