#pragma once

#include "structured_info.h"

#include <saas/library/daemon_base/daemon/messages.h>
#include <saas/rtyserver/common/thread_status.h>
#include <saas/util/guarded_object.h>

#include <kernel/multipart_archive/statistic/archive_info.h>

#include <library/cpp/balloc/setup/alloc.h>
#include <library/cpp/deprecated/atomic/atomic.h>
#include <library/cpp/json/json_value.h>

#include <util/datetime/base.h>
#include <util/generic/map.h>
#include <util/generic/maybe.h>
#include <util/generic/ptr.h>
#include <util/generic/string.h>

class IIndexController;

class TMessageCollectServerInfo final : public TCollectServerInfo {
private:
    struct TIndexInfo {
        TMaybeFail<int> Count;
        TMaybeFail<int> CountWithnoDel;
        TMaybeFail<int> CountSearchable;
        TMaybeFail<int> HasSearcher;
        TMaybeFail<int> Cache;
        TMaybeFail<ui64> Timestamp;
        TMaybeFail<TString> Type;
        TMaybeFail<TString> Dir;
        TMaybeFail<TString> Realm;
        TMaybeFail<ui64> AddCount;
        TMaybeFail<ui64> DelCount;
        TMaybeFail<ui64> UpdCount;
        TMaybeFail<ui64> LockedMemorySizeInBytes;
        TMaybeFail<ui64> IndexSizeInBytes;

        NJson::TJsonValue GetJsonInfo() const;
    };

    TAtomic DiskQueueSize;
    TAtomic MemoryQueueSize;
    TAtomic MergerTasks;
    TThreadStatus MergerStatus;
    TAtomic RepairerTasks;
    TAtomic MemoryIndexersCount;
    TAtomic DocsInDiskIndexers;
    TAtomic DocsInFinalIndexes;
    TAtomic LockedMemorySizeInBytes;
    TAtomic DocsInMemoryIndexes;
    TAtomic SearchableDocs;
    TAtomic ClosingIndexers;
    TMap<TString, unsigned> IndexerClientsCount;
    TMap<TString, unsigned> IndexerConnectionsCount;
    TMap<TString, unsigned> IndexerRequestsCount;

    TMap<TString, TIndexInfo> IndexInfo;
    TMap<ui32, float> DiskIndexRps;
    TMap<ui32, float> MemoryIndexRps;
    TMap<ui32, float> HttpSearchRps;
    TMap<ui32, float> BaseSearchRps;
    TMap<ui32, float> NehSearchRps;
    TMap<ui32, float> FailedSearchRps;
    TString Status;
    ui64 DefaultKps = 0;
    ui64 SearchSourcesCount = 0;
    ui64 ActiveRepliers = 0;
    ui64 ActiveContexts = 0;
    ui64 IndexTimestamp = 0;
    TDuration UpTime;
    TFilesSizeInfo FilesSizeInfo;
    TString CurrentSyncResource;
    TString LastSyncResource;
    TMutex Mutex;

    TMap<TString, IStructuredInfo::TPtr> ComponentsInfo;

    ui32 FactorsCount = 0;
    NJson::TJsonValue FactorsConfig;
    NJson::TJsonValue FactorsUsage;
    NJson::TJsonValue MergerTasksInfo;

    TAtomic InfoAddCount = 0;
    TAtomic InfoDeleteCount = 0;
    TAtomic InfoUpdateCount = 0;
    NRTYArchive::TArchiveInfo FullArcInfo;
    TMutex ArcMutex;
    bool PersistentSearchBan = false;
    bool SlotInfoSearchBan = false;
    bool DocfetcherSearchBan = false;
    bool SearchEnabled = false;
    bool IndexingEnabled = false;

public:
    void AddComponentInfo(IStructuredInfo::TPtr info) {
        if (!!info) {
            ComponentsInfo[info->GetName()] = info;
        }
    }

    void AddMultipartArchiveInfo(const NRTYArchive::TArchiveInfo& info) {
        TGuard<TMutex> g(ArcMutex);
        FullArcInfo.Add(info);
    }

    NJson::TJsonValue GetFullArcInfo() const {
        NJson::TJsonValue json;
        FullArcInfo.ToJson(json);
        return json;
    }

    const TMap<TString, TIndexInfo>& GetIndexInfo() const {
        return IndexInfo;
    }

    void DocumentsInfoAdd(ui64 value) {
        AtomicAdd(InfoAddCount, value);
    }

    void DocumentsInfoDelete(ui64 value) {
        AtomicAdd(InfoDeleteCount, value);
    }

    void DocumentsInfoUpdate(ui64 value) {
        AtomicAdd(InfoUpdateCount, value);
    }

    void SetIndexerClientsCount(TString name, unsigned value) {
        IndexerClientsCount[name] = value;
    }

    void SetIndexerConnectionsCount(TString name, unsigned value) {
        IndexerConnectionsCount[name] = value;
    }

    void SetIndexerRequestsCount(TString name, unsigned value) {
        IndexerRequestsCount[name] = value;
    }

    TMap<TString, unsigned>& GetIndexerClientsCount() {
        return IndexerClientsCount;
    }

    TMap<TString, unsigned>& GetIndexerConnectionsCount() {
        return IndexerConnectionsCount;
    }

    TMap<TString, unsigned>& GetIndexerRequestsCount() {
        return IndexerRequestsCount;
    }

    void AddMergerTaskInfo(NJson::TJsonValue info) {
        MergerTasksInfo.AppendValue(info);
    }

    NJson::TJsonValue GetIndexerClientsCountInfo() const;

    NJson::TJsonValue GetBallocOptionsInfo() const;

    bool IsAllCachesUsage() const;

    explicit TMessageCollectServerInfo(bool isHumanReadable = false)
        : TCollectServerInfo(isHumanReadable)
    {
        Prepare(); // WTF?
    }

    void Prepare() override;

    void AddMemoryIndexersCount() {
        AtomicIncrement(MemoryIndexersCount);
    }

    unsigned GetMemoryIndexersCount() {
        return MemoryIndexersCount;
    }

    void AddDocsInDiskIndexers(unsigned value) {
        AtomicAdd(DocsInDiskIndexers, value);
    }

    void AddIndexInfo(const IIndexController& info);

    void AddDocsInFinalIndexes(unsigned value) {
        AtomicAdd(DocsInFinalIndexes, value);
    }

    void AddDocsInMemoryIndexes(unsigned value) {
        AtomicAdd(DocsInMemoryIndexes, value);
    }

    void AddLockedMemorySizeInBytes(unsigned value) {
        AtomicAdd(LockedMemorySizeInBytes, value);
    }

    void AddSizesInfo(TFilesSizeInfo& info) {
        FilesSizeInfo.Merge(info);
    }

    void AddSearchableDocs(unsigned value) {
        AtomicAdd(SearchableDocs, value);
    }

    void AddClosingIndexers() {
        AtomicIncrement(ClosingIndexers);
    }

    NJson::TJsonValue GetCachesStateInfo();

    NJson::TJsonValue GetIndexesInfo();

    unsigned GetClosingIndexers() {
        return AtomicGet(ClosingIndexers);
    }

    void SetCachesStates(const TMap<TString, bool>& cachesStates);

    unsigned GetDocsInDiskIndexers() {
        return AtomicGet(DocsInDiskIndexers);
    }

    unsigned GetDocsInFinalIndexes() {
        return AtomicGet(DocsInFinalIndexes);
    }

    unsigned GetDocsInMemoryIndexes() {
        return AtomicGet(DocsInMemoryIndexes);
    }

    unsigned GetSearchableDocs() {
        return AtomicGet(SearchableDocs);
    }

    ui64 GetLockedMemorySizeInBytes() {
        return AtomicGet(LockedMemorySizeInBytes);
    }

    void AddRepairerTasks(unsigned value) {
        AtomicAdd(RepairerTasks, value);
    }

    unsigned GetRepairerTasks() {
        return AtomicGet(RepairerTasks);
    }

    void AddMergerTasks(unsigned value) {
        AtomicAdd(MergerTasks, value);
    }

    unsigned GetMergerTasks() {
        return AtomicGet(MergerTasks);
    }

    TThreadStatus GetMergerStatus() const {
        return MergerStatus;
    }

    void SetMergerStatus(TThreadStatus status) {
        MergerStatus = status;
    }

    void SetStatus(TString status) {
        Status = status;
    }

    void SetCurrentSyncResource(TString resourceName) {
        CurrentSyncResource = resourceName;
    }

    void SetLastSyncResource(TString resourceName) {
        LastSyncResource = resourceName;
    }

    void SetUptime(TDuration upTime) {
        UpTime = upTime;
    }

    TDuration GetUptime() const {
        return UpTime;
    }

    TString GetStatus() const {
        return Status;
    }

    unsigned GetDiskQueueSize() const;

    unsigned GetMemoryQueueSize() {
        return AtomicGet(MemoryQueueSize);
    }
    typedef TGuardedPtr<TMap<ui32, float>, TMutex, TGuard<TMutex> > TRpsMapPtr;
    TRpsMapPtr GetDiskIndexRps() {
        return TRpsMapPtr(&DiskIndexRps, Mutex);
    }

    TRpsMapPtr GetMemoryIndexRps() {
        return TRpsMapPtr(&MemoryIndexRps, Mutex);
    }

    TRpsMapPtr GetHttpSearchRps() {
        return TRpsMapPtr(&HttpSearchRps, Mutex);
    }

    TRpsMapPtr GetBaseSearchRps() {
        return TRpsMapPtr(&BaseSearchRps, Mutex);
    }

    TRpsMapPtr GetNehSearchRps() {
        return TRpsMapPtr(&NehSearchRps, Mutex);
    }

    TRpsMapPtr GetFailedSearchRps() {
        return TRpsMapPtr(&FailedSearchRps, Mutex);
    }

    void AddMemoryQueueSize(unsigned value) {
        AtomicAdd(MemoryQueueSize, value);
    }

    void AddDiskQueueSize(unsigned value) {
        AtomicAdd(DiskQueueSize, value);
    }

    void SetDefaultKps(ui64 kps) {
        DefaultKps = kps;
    }

    ui64 GetDefaultKps() {
        return DefaultKps;
    }

    ui64 GetActiveContexts() const {
        return ActiveContexts;
    }

    ui64 GetActiveRepliers() const {
        return ActiveRepliers;
    }

    void SetActiveContexts(ui64 count) {
        ActiveContexts = count;
    }

    void SetActiveRepliers(ui64 count) {
        ActiveRepliers = count;
    }

    void SetSearchSourcesCount(ui64 count) {
        SearchSourcesCount = count;
    }

    ui64 GetSearchSourcesCount() {
        return SearchSourcesCount;
    }

    ui32 GetFactorsCount() const {
        return FactorsCount;
    }

    const NJson::TJsonValue& GetFactorsConfig() const {
        return FactorsConfig;
    }

    const NJson::TJsonValue& GetFactorsUsage() const {
        return FactorsUsage;
    }

    void SetFactorsCount(const ui32 value) {
        FactorsCount = value;
    }

    void SetFactorsConfig(const NJson::TJsonValue& value) {
        FactorsConfig = value;
    }

    void SetFactorsUsage(const NJson::TJsonValue& value) {
        FactorsUsage = value;
    }

    void SetPersistentSearchBan(bool exists) {
        PersistentSearchBan = exists;
    }

    void SetSlotInfoSearchBan(bool exists) {
        SlotInfoSearchBan = exists;
    }

    void SetDocfetcherSearchBan(bool exists) {
        DocfetcherSearchBan = exists;
    }

    void SetSearchEnabled(bool enabled) {
        SearchEnabled = enabled;
    }

    void SetIndexingEnabled(bool enabled) {
        IndexingEnabled = enabled;
    }

    void Fill(TServerInfo& info) override;
};
