#pragma once

#include "dispatch_config.h"

#include <saas/library/daemon_base/config/daemon_config.h>
#include <saas/library/daemon_base/config/watchdog_opts.h>
#include <saas/library/daemon_base/module/module.h>
#include <saas/library/flow/mirror.h>
#include <saas/indexerproxy/adapters/interface_adapter.h>
#include <saas/indexerproxy/export/config.h>
#include <saas/library/searchmap/parsers/parser.h>
#include <saas/library/tvm/tvm.h>

#include <kernel/qtree/request/reqattrlist.h>

#include <library/cpp/http/server/options.h>

#include <util/generic/ptr.h>
#include <util/generic/utility.h>
#include <util/string/util.h>

class TProxyConfig;

struct TProxyServiceConfig {
public:
    bool IndexationDisabled = false;
    bool Realtimable = true;
    bool DeferredQueueEnabled = true;
    TString ServiceName = "default";
    TString SessionPrefix = Default<TString>();
    ui64 SpaceLimitInMBytes = Max<ui64>();
    ui32 MaxDocsInWorkPerBackend = 4;
    ui64 QueuePartSizeLimit = 10 * (1 << 20);

    TString DeferredMessagesLifetime = "0";
    TString InteractionTimeout = "500ms";
    TString ConnectionTimeout = "100ms";

    TSet<TString> DistributionMetrics;

    TDuration DeferredMessagesLifetimeDuration = TDuration::Zero();
    TDuration InteractionTimeoutDuration = TDuration::MilliSeconds(500);
    TDuration ConnectionTimeoutDuration = TDuration::MilliSeconds(100);

    ui32 SendAttemptsCount = 4;
    ui32 MaxInFlightForInstant = Max<ui32>();
    bool LoggingEnabled = true;

    float Quorum = 0.f;

    TMaybe<NSaas::TTvmConfig> TvmConfig;

public:
    void Init(const TString& serviceName, const TYandexConfig::Section& configSection);
    TString ToString() const;
};

class TProxyServicesConfig {
private:
    TMap<TString, TProxyServiceConfig> Configs;
    TProxyServiceConfig DefaultConfig;
public:

    const TProxyServiceConfig& GetDefaultConfig() const {
        return DefaultConfig;
    }

    const TProxyServiceConfig& GetConfig(const TString& serviceName) const {
        if (Configs.contains(serviceName))
            return Configs.find(serviceName)->second;
        return DefaultConfig;
    }

    void Init(const TYandexConfig::Section& configSection);

    TString ToString() const {
        TStringStream ss;
        ss << "<" << "Services" << ">" << Endl;
        for (auto&& i : Configs) {
            ss << i.second.ToString() << Endl;
        }
        ss << "</" << "Services" << ">" << Endl;
        return ss.Str();
    }
};

struct TAdapterConfig: public TAdapterMinimalConfig {
public:
    TAdapterConfig(const TProxyConfig& owner);

    void Init(const TYandexConfig::Directives& directives);
    TString ToString() const;

    const TProxyConfig& GetOwner() const {
        return Owner;
    }
private:
    const TProxyConfig& Owner;
};

struct TExportConfig: public NSaas::TKiwiExportConfig {
public:
    TExportConfig(const TProxyConfig& owner);

    void Init(const TYandexConfig::Directives& directives);
    TString ToString() const;

    const TProxyConfig& GetOwner() const {
        return Owner;
    }
private:
    const TProxyConfig& Owner;
};

struct TFlowMirrorConfig: public TFlowMirror::TConfig {
public:
    void Init(const TYandexConfig::Directives& directives);
    TString ToString() const;
};

class TProxyConfig: public IServerConfig {
public:
    struct THashInfoStructure {
        TString Service;
        TString Adapter;
        THashInfoStructure() {}
        THashInfoStructure(const TString& service, const TString& adapter) {
            Service = service;
            Adapter = adapter;
        }
    };

public:
    TProxyConfig(const TServerConfigConstructorParams& params);
    void InitFromString(const char* configText);
    void Init(const TYandexConfig::Directives& directives);
    TString ToString() const;

    TSet<TString> GetModulesSet() const {
        return TSet<TString>();
    }

    const TDaemonConfig& GetDaemonConfig() const {
        return DaemonConfig;
    }

    inline ui32 GetHttpServerInstances() const {
            return HttpServerInstances;
    }

    const TDaemonConfig::THttpOptions& GetHttpOptionsConfig() const {
        return HttpOptionsConfig;
    }

    const TProxyServicesConfig& GetServicesConfig() const {
        return ServicesConfig;
    }

    const TDispatcherConfig& GetDispConfig() const {
        return DispatcherConfig;
    }

    const TVector<TAdapterConfig>& GetAdaptersConfigVector() const {
        return Adapters;
    }

    const NSearchMapParser::TSearchMap::TServiceMap& GetServiceMap() const {
        return ServiceMap;
    }

    const NSearchMapParser::TSearchMap& GetSearchMap() const {
        return SearchMap;
    }

    const TSet<TString>& GetServices() const {
        return Services;
    }

    const TExportConfig& GetExportConfig() const {
        return ExportConfig;
    }

    const TString& GetAuthKeyWord() const {
        return AuthKeyWord;
    }

    const TVector<TString>& GetWatchdogOptionsFiles() const {
        return WatchdogOptionsFiles;
    }

    const TString& GetDumpFile() const {
        return DumpFile;
    }

    const TString& GetDumpServices() const {
        return DumpServices;
    }

    const TFlowMirror::TConfig& GetFlowMirrorConfig() const {
        return FlowMirrorConfig;
    }

    bool DecodeServiceHash(const TString serviceHash, THashInfoStructure& info) const {
        auto i = DecodeHashToInfo.find(serviceHash);
        if (i == DecodeHashToInfo.end())
            return false;
        info = i->second;
        return true;
    }

    bool GetUsesSmartQueues() const {
        return UseSmartQueues;
    }

    const NSearchMapParser::TServiceSpecificOptions* GetServiceInfo(const TString& serviceName) const;
public:
    TString IndexLog;
    TVector<TString> WatchdogOptionsFiles;
    ui32 SenderThreads;

private:
    THolder<TAnyYandexConfig> Impl;

    ui32 HttpServerInstances;
    TDaemonConfig::THttpOptions HttpOptionsConfig;
    TDaemonConfig DaemonConfig;
    TDispatcherConfig DispatcherConfig;
    TExportConfig ExportConfig;
    TString SearchMapFile;
    THolder<NSearchMapParser::ISearchMapParser> SearchMapParser;
    NSearchMapParser::TSearchMap::TServiceMap ServiceMap;
    NSearchMapParser::TSearchMap SearchMap;
    TSet<TString> Services;
    TVector<TAdapterConfig> Adapters;
    TProxyServicesConfig ServicesConfig;
    TString AuthKeyWord;
    TString DumpFile;
    TString DumpServices;
    TConfigPatcher& Preprocessor;
    TFlowMirrorConfig FlowMirrorConfig;
    TMap<TString, THashInfoStructure> DecodeHashToInfo;
    bool UseSmartQueues = true;
};


class TProxyWatchdogSubsciber : public IWatchdogOptionSubscriber {
private:
    double MinRank;
    TWatchdogSubscription Subscription;
public:
    double GetMinRank() const {
        return MinRank;
    }

public:
    TProxyWatchdogSubsciber();

    void OnWatchdogOption(const TString& key, const TString& value) override;

    void Subscribe(IWatchdogOptions& s) {
        Subscription = s.Subscribe(this);
    }
    void Unsubscribe() {
        Subscription.Reset();
    }
};
