#pragma once

#include "entity.h"

#include <logbroker/public/api/grpc/config_manager.grpc.pb.h>
#include <saas/library/persqueue/configuration/proto/types.pb.h>


namespace NSaasLB {
    using TRemoteMirrorRuleKey = std::tuple<TString, EDataCenter, TString, TString, ELogbrokerName>;

    class TRemoteMirrorRule {
    public:
        TRemoteMirrorRule() = default;
        TRemoteMirrorRule(
            const TString& topic,
            EDataCenter dataCenter,
            const TString& originTopic,
            const TString& originConsumer,
            ELogbrokerName originLogbroker
        );
        TRemoteMirrorRule(const NLogBroker::RemoteMirrorRuleAdmin& remoteMirrorRule);

        TRemoteMirrorRuleKey GetKey() const;
        TString GetTopicPath() const;
        EDataCenter GetDataCenter() const;

        NLogBroker::SingleModifyRequest GetAddCommand(const TString& oAuthToken) const;
        NLogBroker::SingleModifyRequest GetRemoveCommand() const;

        bool operator== (const TRemoteMirrorRule& other) const;
        bool operator< (const TRemoteMirrorRule& other) const;

    private:
        void FillRuleRequestKey(NLogBroker::RemoteMirrorRuleKey& key) const;
        void FillRuleRequestProperties(NLogBroker::RemoteMirrorRuleProperties& props) const;

    private:
        TString Topic;
        EDataCenter DataCenter;

        TString OriginTopic;
        TString OriginConsumer;
        ELogbrokerName OriginLogbroker;
    };


    class TRemoteMirrorRuleStorage {
    public:
        std::optional<NLogBroker::SingleModifyRequest> Add(const TRemoteMirrorRule& rule, const TString& oAuthToken);
        std::optional<NLogBroker::SingleModifyRequest> Remove(const TRemoteMirrorRule& rule);

        TVector<TRemoteMirrorRule> GetForTopic(const TString& topic) const;

        inline bool Exists(const TRemoteMirrorRule& rule) const {
            return KeyToRule.contains(rule.GetKey());
        };

        template <class TProtoEntity>
        void Load(const TProtoEntity& entity) {
            for (auto&& rule : entity.remote_mirror_rules()) {
                const TRemoteMirrorRule& entityRule = rule;
                if (!Exists(entityRule)) {
                    KeyToRule[entityRule.GetKey()] = entityRule;
                    TopicToRules[entityRule.GetTopicPath()].push_back(rule);
                }
            }
        }
    private:
        THashMap<TString, TVector<TRemoteMirrorRule>> TopicToRules;
        THashMap<TRemoteMirrorRuleKey, TRemoteMirrorRule> KeyToRule;
    };
}
