from libcpp cimport bool
from util.generic.string cimport TString
from util.generic.vector cimport TVector
from util.generic.ptr cimport THolder, MakeHolder

import saas.library.persqueue.configuration.service.modify_manager.proto.changes_pb2 as changes_proto
import saas.library.persqueue.configuration.proto.description_pb2 as description_proto
import saas.library.persqueue.configuration.proto.types_pb2 as types_proto

import enum

include 'util.pyx'


cdef extern from "saas/library/persqueue/configuration/proto/types.pb.h" namespace "NSaasLB" nogil:
    cdef cppclass TServiceConfig:
        TString SerializeAsString() except +

    cdef cppclass TNamespaceConfig:
        TNamespaceConfig() except +
        bool ParseFromString(const TString& str) except +
        TString SerializeAsString() except +

    ctypedef enum ELogbrokerName 'NSaasLB::ELogbrokerName':
        pass

    ctypedef enum EDataCenter 'NSaasLB::EDataCenter':
        pass

cdef extern from "saas/library/persqueue/configuration/proto/description.pb.h" namespace "NSaasLB" nogil:
    cdef cppclass TNamespaceDescription:
        TString SerializeAsString() except +

cdef extern from "saas/library/persqueue/configuration/service/modify_manager/proto/changes.pb.h" namespace "NSaasLB" nogil:
    cdef cppclass TNamespaceModifyRequest:
        TString SerializeAsString() except +

cdef extern from "saas/library/persqueue/configuration/namespace/namespace.h" namespace "NSaasLB" nogil:
    cdef cppclass TNamespaceManager:
        TNamespaceManager() except +
        TNamespaceManager(const TString& ns) except +
        void Create(const TString& name, const TNamespaceConfig& config) except +
        void Modify(const TNamespaceConfig& config) except +
        void Remove() except +

        void Apply() except +
        TNamespaceModifyRequest GetChanges() except +

        TString GetNamespaceConfigPath(const TString& name) except +

        const TString& GetName() except +
        const TNamespaceConfig& GetConfig() except +
        TNamespaceDescription Describe() except +

        TServiceConfig CreateServiceConfig(
            const TString& serviceName,
            const TString& ctype,
            ELogbrokerName logbroker,
            const TVector[EDataCenter]& dataCenters,
            const TVector[TString]& ytDeliveryClusters,
            optional[ELogbrokerName] logbrokerMirror,
            optional[TString] topicsPath,
            optional[TString] mirrorTopicsPath,
            optional[TString] consumersPath,
            optional[TString] mirrorConsumersPath,
            optional[TString] locksPath,
            optional[TString] deployManagerHost,
            optional[TVector[TString]] gencfgGroups
        ) except +


cdef class NamespaceManager:
    cdef THolder[TNamespaceManager] __namespace

    def __dealloc__(self):
        with nogil:
            self.__namespace.Destroy()

    def __init__(self, ns=None):
        cdef TString c_namespace
        if ns is not None:
            c_namespace = _to_string(ns)
            with nogil:
                self.__namespace = MakeHolder[TNamespaceManager](c_namespace)
        else:
            with nogil:
                self.__namespace = MakeHolder[TNamespaceManager]()

    def create(self, name, ns_config):
        cdef TNamespaceConfig c_ns_config
        cdef bool Y_PROTOBUF_SUPPRESS_NODISCARD
        Y_PROTOBUF_SUPPRESS_NODISCARD = c_ns_config.ParseFromString(ns_config.SerializeToString())
        cdef TString c_namespace = _to_string(name)
        with nogil:
            self.__namespace.Get().Create(c_namespace, c_ns_config)

    def modify(self, ns_config):
        cdef TNamespaceConfig c_ns_config
        cdef bool Y_PROTOBUF_SUPPRESS_NODISCARD
        Y_PROTOBUF_SUPPRESS_NODISCARD = c_ns_config.ParseFromString(ns_config.SerializeAsString())
        with nogil:
            self.__namespace.Get().Modify(c_ns_config)

    def remove(self):
        with nogil:
            self.__namespace.Get().Remove()

    def apply(self):
        with nogil:
            self.__namespace.Get().Apply()

    def modify(self):
        cdef TString changesStr
        with nogil:
            changesStr = self.__namespace.Get().GetChanges().SerializeAsString()
        changes = changes_proto.TNamespaceModifyRequest()
        changes.ParseFromString(changesStr)
        return changes

    def get_ns_config_path(self, ns_name):
        cdef TString c_ns_name = _to_string(ns_name)
        cdef TString path
        with nogil:
            path = self.__namespace.Get().GetNamespaceConfigPath(c_ns_name)
        return _to_py_str(path)

    def get_name(self):
        cdef TString name
        with nogil:
            name = self.__namespace.Get().GetName()
        return _to_py_str(name)

    def get_config(self):
        cdef TString config_str
        with nogil:
            config_str = self.__namespace.Get().GetConfig().SerializeAsString()
        config = types_proto.TNamespaceConfig()
        config.ParseFromString(config_str)
        return config

    def describe(self):
        cdef TString description_str
        with nogil:
            description_str = self.__namespace.Get().Describe().SerializeAsString()
        description = description_proto.TNamespaceDescription()
        description.ParseFromString(description_str)
        return description

    def create_service_config(
        self,
        service_name,
        ctype,
        ELogbrokerName logbroker,
        TVector[EDataCenter] data_centers,
        yt_delivery_clusters,
        logbroker_mirror=None,
        topics_path=None,
        mirror_topics_path=None,
        consumers_path=None,
        mirror_consumers_path=None,
        locks_path=None,
        deploy_manager_host=None,
        gencfg_groups=None
    ):
        cdef TString c_service_name = _to_string(service_name)
        cdef TString c_ctype = _to_string(ctype)
        cdef TVector[TString] c_yt_delivery_clusters = _to_strings_vector(yt_delivery_clusters)

        cdef optional[ELogbrokerName] c_logbroker_mirror
        if logbroker_mirror is not None:
            c_logbroker_mirror = optional[ELogbrokerName](logbroker_mirror)

        cdef optional[TString] c_topics_path
        if topics_path is not None:
            c_topics_path = optional[TString](_to_string(topics_path))

        cdef optional[TString] c_mirror_topics_path
        if mirror_topics_path is not None:
            c_mirror_topics_path = optional[TString](_to_string(mirror_topics_path))

        cdef optional[TString] c_consumers_path
        if consumers_path is not None:
            c_consumers_path = optional[TString](_to_string(consumers_path))

        cdef optional[TString] c_mirror_consumers_path
        if mirror_consumers_path is not None:
            c_mirror_consumers_path = optional[TString](_to_string(mirror_consumers_path))

        cdef optional[TString] c_locks_path
        if locks_path is not None:
            c_locks_path = optional[TString](_to_string(locks_path))

        cdef optional[TString] c_deploy_manager_host
        if deploy_manager_host is not None:
            c_deploy_manager_host = optional[TString](_to_string(deploy_manager_host))

        cdef optional[TVector[TString]] c_gencfg_groups
        if gencfg_groups is not None:
            c_gencfg_groups = optional[TVector[TString]](_to_strings_vector(gencfg_groups))

        cdef TString config_str
        with nogil:
            config_str = self.__namespace.Get().CreateServiceConfig(
                c_service_name,
                c_ctype,
                logbroker,
                data_centers,
                c_yt_delivery_clusters,
                c_logbroker_mirror,
                c_topics_path,
                c_mirror_topics_path,
                c_consumers_path,
                c_mirror_consumers_path,
                c_locks_path,
                c_deploy_manager_host,
                c_gencfg_groups
            ).SerializeAsString()
        config = types_proto.TServiceConfig()
        config.ParseFromString(config_str)
        return config
