#pragma once

#include "entity.h"

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

#include <util/generic/hash.h>
#include <util/generic/vector.h>
#include <util/generic/set.h>
#include <util/string/cast.h>
#include <util/string/vector.h>
#include <util/string/join.h>

namespace NSaasLB {

    class TReadRule {
    public:
        TReadRule() = default;
        TReadRule(const TString& topicPath, const TString& consumerPath, EDataCenter dc);
        TReadRule(const NLogBroker::ReadRule& readRule);

        const TString& GetTopicPath() const;
        const TString& GetConsumerPath() const;
        EDataCenter GetDataCenter() const;
        NLogBroker::ReadRule GetProto() const;

        NLogBroker::SingleModifyRequest GetAddCommand() const;
        NLogBroker::SingleModifyRequest GetRemoveCommand() const;

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

        static EDataCenter GetDataCenter(const NLogBroker::ReadRuleKey& readRuleKey);

    private:
        void FillEntity(NLogBroker::ReadRuleKey& readRule) const;

    private:
        TString TopicPath;
        TString ConsumerPath;
        EDataCenter DataCenter;
    };

    class TReadRuleStorage {
    public:
        std::optional<NLogBroker::SingleModifyRequest> Add(const TReadRule& readRule);
        std::optional<NLogBroker::SingleModifyRequest> Remove(const TReadRule& readRule);

        bool Exist(const TReadRule& readRule) const;
        TVector<TReadRule> GetFor(const IEntity& entity) const;

        template <class TProtoEntity>
        void Load(const TProtoEntity& entity) {
            for (auto&& rule : entity.read_rules()) {
                Add(rule);
            }
        }

    private:
        void Remove(
            THashMap<TString, TSet<TReadRule>>& rulesByEntity,
            const TReadRule& readRule,
            const TString& path
        );
        TVector<TReadRule> GetFor(
            const THashMap<TString, TSet<TReadRule>>& rulesByEntity,
            const TString& path
        ) const;

    private:
        THashMap<TString, TSet<TReadRule>> RulesByConsumers;
        THashMap<TString, TSet<TReadRule>> RulesByTopics;
    };

}
