#pragma once

#include <saas/library/persqueue/configuration/proto/description.pb.h>
#include <saas/library/persqueue/configuration/service/modify_manager/proto/changes.pb.h>
#include <saas/library/persqueue/configuration/service/modify_manager/components.h>

#include <util/generic/hash_set.h>
#include <util/generic/hash.h>

namespace NZooKeeper {
    class TZooKeeper;
}

namespace NSaasLB {

    class ILocksCluster : public IComponent<TLocksModifyRequests> {
    public:
        virtual ~ILocksCluster() = default;
        virtual TVector<TString> GetLocks(const TString& path) = 0;
        virtual void Add(const TString& path, const TString& resource) = 0;
        virtual void Remove(const TString& path, const TString& resource) = 0;

        virtual TLockDescription GetDescribed(const TString& path, const TString& resource) = 0;
    };

    class TZooKeeperLocks : public ILocksCluster {
    public:
        TZooKeeperLocks(const TString& servers);
        ~TZooKeeperLocks();
        TVector<TString> GetLocks(const TString& path) override;
        void Add(const TString& path, const TString& resource) override;
        void Remove(const TString& path, const TString& resource) override;

        TLockDescription GetDescribed(const TString& path, const TString& resource) override;

        const TLocksModifyRequests& GetChanges() const override;
        void Apply(ui32 changesCount) override;

    private:
        TString GetNodePath(const TString& path, const TString& resource);
        THashSet<TString>& LoadLocksByPath(const TString& path);
        TVector<TString> LoadItemsByPath(const TString& path);

        void RecursiveCreateNode(const TString& nodePath);
        void RecursiveRemoveNode(const TString& nodePath);

        TString Encode(const TString& resource) const;
        TString Decode(const TString& resource) const;

        void AddRequest(EChangeAction action, const TString& path, const TString& resource);
    private:
        const TString Servers;
        THolder<NZooKeeper::TZooKeeper> Storage;

        THashMap<TString, THashSet<TString>> LocksByPath;

        TLocksModifyRequests Changes;
    };

}
