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

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 enum

include 'util.pyx'


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

    ctypedef enum EServicePermission 'NSaasLB::EServicePermission':
        pass

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

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

cdef extern from "saas/library/persqueue/configuration/service/service.h" namespace "NSaasLB" nogil:
    cdef cppclass TServiceConfiguration:
        TServiceConfiguration(
            const TString& ns,
            const TString& name,
            const TString& ctype,
            optional[TServiceConfig] serviceConfig = {},
            optional[TVector[TString]] shards = {},
            optional[ui32] replicas = {},
            optional[TString] gencfgTag = {},
            bool noRemove = false,
            bool forceRemove = false,
            optional[TString] logbrokerToken = {}
        ) except +
        void Create(const TVector[ui32]& writeTvm, const TVector[ui32]& readTvm) except +
        void Remove() except +
        void UpdateConsumers() except +
        void UpdateTopics() except +
        void UpdateLocks() except +
        void UpdateYtDelivery() except +
        void GrantPermission(EServicePermission permission, const TVector[ui32]& tvm) except +
        void RevokePermission(EServicePermission permission, const TVector[ui32]& tvm) except +
        TServiceDescription Describe() except +
        const TServiceChanges& GetChanges() except +
        void Apply() except +



cdef class ServiceConfiguration:
    cdef THolder[TServiceConfiguration] __service

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

    def __init__(
        self,
        namespace,
        name,
        ctype,
        service_config=None,
        shards=None,
        replicas=None,
        gencfg_tag=None,
        bool no_remove=False,
        bool force_remove=False,
        logbroker_token=None
    ):
        cdef TString c_namespace = _to_string(namespace)
        cdef TString c_name = _to_string(name)
        cdef TString c_ctype = _to_string(ctype)

        cdef optional[TServiceConfig] c_service_config
        cdef bool Y_PROTOBUF_SUPPRESS_NODISCARD
        if service_config is not None:
            c_service_config = optional[TServiceConfig](TServiceConfig())
            Y_PROTOBUF_SUPPRESS_NODISCARD = c_service_config.value().ParseFromString(service_config.SerializeToString())

        cdef optional[TVector[TString]] c_shards
        if shards is not None:
            c_shards = optional[TVector[TString]](_to_strings_vector(shards))

        cdef optional[ui32] c_replicas
        if replicas is not None:
            c_replicas = optional[ui32](replicas)

        cdef optional[TString] c_gencfg_tag
        if gencfg_tag is not None:
            c_gencfg_tag = optional[TString](_to_string(gencfg_tag))

        cdef optional[TString] c_logbroker_token
        if logbroker_token is not None:
            c_logbroker_token = optional[TString](_to_string(logbroker_token))

        with nogil:
            self.__service = MakeHolder[TServiceConfiguration](
                c_namespace,
                c_name,
                c_ctype,
                c_service_config,
                c_shards,
                c_replicas,
                c_gencfg_tag,
                no_remove,
                force_remove,
                c_logbroker_token
            )

    def create(self, write_tvm_values=None, read_tvm_values=None):
        cdef TVector[ui32] c_write_tvm_values
        cdef TVector[ui32] c_read_tvm_values
        if write_tvm_values is not None:
            c_write_tvm_values = _to_ui32_vector(write_tvm_values)
        if read_tvm_values is not None:
            c_read_tvm_values = _to_ui32_vector(read_tvm_values)
        with nogil:
            self.__service.Get().Create(c_write_tvm_values, c_read_tvm_values)

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

    def update_consumers(self):
        with nogil:
            self.__service.Get().UpdateConsumers()

    def update_topics(self):
        with nogil:
            self.__service.Get().UpdateTopics()

    def update_locks(self):
        with nogil:
            self.__service.Get().UpdateLocks()

    def update_yt_delivery(self):
        with nogil:
            self.__service.Get().UpdateYtDelivery()

    def grant_permission(self, EServicePermission permission, TVector[ui32] tvm_values):
        with nogil:
            self.__service.Get().GrantPermission(permission, tvm_values)

    def revoke_permission(self, EServicePermission permission, TVector[ui32] tvm_values):
        with nogil:
            self.__service.Get().RevokePermission(permission, tvm_values)

    def describe(self):
        cdef TString descriptionStr
        with nogil:
            descriptionStr = self.__service.Get().Describe().SerializeAsString()
        description = description_proto.TServiceDescription()
        description.ParseFromString(descriptionStr)
        return description

    def get_changes(self):
        cdef TString changesStr
        with nogil:
            changesStr = self.__service.Get().GetChanges().SerializeAsString()
        changes = changes_proto.TServiceChanges()
        changes.ParseFromString(changesStr)
        return changes

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