#pragma once

#include <saas/library/persqueue/configuration/service/modify_manager/manager.h>

namespace NSaasLB {
    class TServiceConfiguration {
    public:
        TServiceConfiguration(
            const TString& ns,
            const TString& name,
            const TString& ctype,
            bool noRemove = false,
            bool forceRemove = false,
            std::optional<TString> logbrokerToken = {}
        );

        TServiceConfiguration(
            const TString& ns,
            const TString& name,
            const TString& ctype,
            std::optional<TServiceConfig> serviceConfig,
            std::optional<TVector<TString>> shards,
            std::optional<ui32> replicas,
            std::optional<TString> gencfgTag,
            bool noRemove = false,
            bool forceRemove = false,
            std::optional<TString> logbrokerToken = {}
        );

        void Create(const TVector<ui32>& writeTvm = {}, const TVector<ui32>& readTvm = {});
        void Remove();

        void UpdateConsumers();
        void UpdateTopics();
        void UpdateLocks();
        void UpdateYtDelivery();

        void GrantPermission(EServicePermission permission, const TVector<ui32>& tvm);
        void RevokePermission(EServicePermission permission, const TVector<ui32>& tvm);

        TServiceDescription Describe();

        TServiceChanges GetChanges() const;
        void Apply();

    private:
        void Init(
            std::optional<TString> logbrokerToken,
            std::optional<TServiceConfig> serviceConfig = {},
            std::optional<TVector<TString>> shards = {},
            std::optional<ui32> replicas = {},
            std::optional<TString> gencfgTag = {}
        );

        inline TString GetTopicsPath(ELogbrokerKind kind) const;
        inline TString GetConsumersPath(ELogbrokerKind kind) const;

        void LoadServiceInfo(
            std::optional<TVector<TString>> shards,
            std::optional<ui32> replicas,
            std::optional<TString> gencfgTag
        );

        TMap<TString, EDataCenter> GetConsumerToDataCenter(const TVector<TString>& consumers);
        TMap<TString, TString> GetOriginToMirrorTopic(
            const TVector<TString>& originTopics,
            const TVector<TString>& mirrorTopics
        );

        void RemoveReadRules(const TVector<TString>& topics, const TVector<TString>& consumers, ELogbrokerKind kind);
        void UpdateReadRules(ELogbrokerKind kind);
        void UpdateRemoteMirrorRules();
        void UpdateLocks(const TVector<TString>& consumers);

        TVector<TString> GetTargetConsumers(ELogbrokerKind kind) const;
        TVector<TString> GetTargetTopics(ELogbrokerKind kind) const;

        void UpdateTopics(ELogbrokerKind kind, bool authRequired = false);
        void UpdateConsumers(ELogbrokerKind kind);

        void CreateTopics(const TVector<TString>& topics, ELogbrokerKind kind, bool authRequired);
        void RemoveTopics(const TVector<TString>& topics, ELogbrokerKind kind);

        void GrantPermission(EServicePermission permission, const TVector<ui32>& tvm, ELogbrokerKind kind);
        void RevokePermission(EServicePermission permission, const TVector<ui32>& tvm, ELogbrokerKind kind);

        bool UsedOnlyByThisService(const TVector<TString>& topics, ELogbrokerKind kind);
        bool UsedOnlyByThisService(const TString& topic, ELogbrokerKind kind);

        static bool IsInternalConsumer(const TString& consumer);
    private:
        TString Namespace;
        TString Name;
        TString Ctype;

        TNamespaceConfig NamespaceConfig;
        TServiceConfig ServiceConfig;

        bool NoRemove;
        bool ForceRemove;

        TVector<TString> Shards;
        ui32 Replicas = 0;

        THolder<TModifyManager> ModifyManager;
    };

}
