#include "configs.h"

const TString SERVICE_CONFIG_LABEL = "Service";
const TString PQ_LIB_CONFIG_LABEL = "PQLibSettings";
const TString BAD_SEARCHMAP_CONFIG_LABEL = "Searchmap";
const TString SEARCHMAP_CONFIG_LABEL = "SearchMap";
const TString TVM_CONFIG_LABEL = "TVM";
const TString CHECK_MESSAGE_SETTINGS_LABEL = "CheckMessage";
const TString WRITER_CONFIG_LABEL = "Writer";
const TString HTTP_OPTIONS_CONFIG_LABEL = "HttpOptions";
const TString CONTROLLER_CONFIG_LABEL = "Controller";
const TString SERVER_CONFIG_LABEL = "Server";
const TString TELEMETRY_CONFIG_LABEL = "Telemetry";

namespace {
    template <class T>
    void PrintSections(IOutputStream& so, const TVector<T>& sections, const TString& sectionName) {
        for (auto&& section : sections) {
            so << "<" << sectionName << ">" << Endl;
            section.Print(so);
            so << "</" << sectionName << ">" << Endl;
        }
    }
};

namespace NSaasPush {
    void InitCheckMessageSettings(const TYandexConfig::Section* section, NSaas::TCheckMessageSettings& settings) {
        const TYandexConfig::Directives& directives = section->GetDirectives();
        if (directives.contains("Disabled")) {
            settings.SetDisabled(directives.Value<bool>("Disabled"));
        }
        if (directives.contains("MaxSizeBytes")) {
            settings.SetCheckMaxSizeBytes(directives.Value<ui32>("MaxSizeBytes"));
        }
        if (directives.contains("Attributes")) {
            settings.SetCheckAttributes(directives.Value<bool>("Attributes"));
        }
        if (directives.contains("KeyPrefixType")) {
            settings.SetKeyPrefixCheckType(directives.Value<NSaas::EKeyPrefixCheckType>("KeyPrefixType"));
        }
    }

    void PrintCheckMessageSettings(IOutputStream& so, const NSaas::TCheckMessageSettings& settings) {
        so << "Disabled: " << settings.GetDisabled() << Endl;
        so << "MaxSizeBytes : " << settings.GetCheckMaxSizeBytes() << Endl;
        so << "Attributes : " << settings.GetCheckAttributes() << Endl;
        so << "KeyPrefixType : " << settings.GetKeyPrefixCheckType() << Endl;
    }

    TServiceInfo::TServiceInfo() {
        CheckMessageSettings.SetCheckMaxSizeBytes(0)
                            .SetKeyPrefixCheckType(NSaas::EKeyPrefixCheckType::any);
    }

    void TServiceInfo::Init(const TYandexConfig::Section* section) {
        const TYandexConfig::Directives& directives = section->GetDirectives();
        const TYandexConfig::TSectionsMap& childs = section->GetAllChildren();

        directives.GetValue("Name", Name);
        directives.GetValue("Ctype", Ctype);
        directives.GetValue("Alias", Alias);
        VERIFY_WITH_LOG(Alias, "Empty alias");
        directives.GetValue("Format", Format);
        directives.GetValue("LoggingEnabled", LoggingEnabled);

        directives.GetValue("ConnectionTimeout", ConnectionTimeout);
        directives.GetValue("WriteTimeout", WriteTimeout);
        directives.GetValue("AttemptsCount", AttemptsCount);

        directives.GetValue("TopicsDir", TopicsDir);
        directives.GetValue("Server", Server);
        directives.GetValue("SourceIdPrefix", SourceIdPrefix);
        if (directives.contains("Codec")) {
            TString codec;
            directives.GetValue("Codec", codec);
            Codec = FromString<NPersQueueCommon::ECodec>(codec);
        }

        TYandexConfig::TSectionsMap::const_iterator tvmSection = childs.find(TVM_CONFIG_LABEL);
        VERIFY_WITH_LOG(tvmSection != childs.end(), "No TVM section in service config");
        TvmConfig.Init(*tvmSection->second);

        TYandexConfig::TSectionsMap::const_iterator checkMessageSection = childs.find(CHECK_MESSAGE_SETTINGS_LABEL);
        if (checkMessageSection != childs.end()) {
            InitCheckMessageSettings(checkMessageSection->second, CheckMessageSettings);
        }
    }

    void TServiceInfo::Print(IOutputStream& so) const {
        so << "Name: " <<Name << Endl;
        so << "Ctype : " << Ctype << Endl;
        so << "Alias : " << Alias << Endl;
        so << "Format : " << Format << Endl;
        so << "LoggingEnabled : " << LoggingEnabled << Endl;

        so << "ConnectionTimeout : " << ConnectionTimeout << Endl;
        so << "WriteTimeout : " << WriteTimeout << Endl;
        so << "AttemptsCount : " << AttemptsCount << Endl;

        so << "TopicsDir : " << TopicsDir << Endl;
        so << "Server : " << Server << Endl;
        so << "SourceIdPrefix : " << SourceIdPrefix << Endl;
        if (Codec) {
            so << "Codec : " << Codec.value() << Endl;
        }

        so << TvmConfig.ToString(TVM_CONFIG_LABEL.c_str());

        so << "<" << CHECK_MESSAGE_SETTINGS_LABEL << ">" << Endl;
        PrintCheckMessageSettings(so, CheckMessageSettings);
        so << "</" << CHECK_MESSAGE_SETTINGS_LABEL << ">" << Endl;
    }

    void TWriterConfig::Init(const TYandexConfig::Section* config) {
        const TYandexConfig::Directives& directives = config->GetDirectives();
        const TYandexConfig::TSectionsMap& childs = config->GetAllChildren();

        directives.GetValue("MessagesLog", MessagesLog);
        directives.GetValue("SleepOnConnectFailure", SleepOnConnectFailure);

        auto section = childs.find(HTTP_OPTIONS_CONFIG_LABEL);
        if (section != childs.end()) {
            const TYandexConfig::Directives& directives = section->second->GetDirectives();
            HttpOptions.Init(directives);
        }

        auto services_range = childs.equal_range(SERVICE_CONFIG_LABEL);
        for (auto it = services_range.first; it != services_range.second; ++it) {
            TServiceInfo service;
            service.Init(it->second);
            Services.push_back(std::move(service));
        }
    }

    void TWriterConfig::Print(IOutputStream& so) const {
        so << "MessagesLog : " << MessagesLog << Endl;
        so << "SleepOnConnectFailure : " << SleepOnConnectFailure << Endl;

        so << HttpOptions.ToString(HTTP_OPTIONS_CONFIG_LABEL);

        PrintSections(so, Services, SERVICE_CONFIG_LABEL);
    }

    void TControllerConfig::Init(const TYandexConfig::Section* config) {
        const TYandexConfig::TSectionsMap& childs = config->GetAllChildren();
        {
            auto httpOptionsSection = childs.find(HTTP_OPTIONS_CONFIG_LABEL);
            if (httpOptionsSection != childs.end()) {
                const TYandexConfig::Directives& directives = httpOptionsSection->second->GetDirectives();
                HttpOptions.Init(directives);
            }
        }
    }

    void TControllerConfig::Print(IOutputStream& so) const {
        so << HttpOptions.ToString(HTTP_OPTIONS_CONFIG_LABEL);
    }

    void TServerConfig::Init(const TYandexConfig::Section* config) {
        const TYandexConfig::Directives& directives = config->GetDirectives();
        const TYandexConfig::TSectionsMap& childs = config->GetAllChildren();

        InitLog(config);
        {
            auto writerSection = childs.find(WRITER_CONFIG_LABEL);
            VERIFY_WITH_LOG(writerSection != childs.end(), "No Writer section");
            WriterConfig.Init(writerSection->second);
        }

        directives.GetValue("UpdateSearchMapPeriod", UpdateSearchMapPeriod);

        auto searchmapRange = childs.equal_range(SEARCHMAP_CONFIG_LABEL);
        if (searchmapRange.first == searchmapRange.second) {
            searchmapRange = childs.equal_range(BAD_SEARCHMAP_CONFIG_LABEL);
        }
        for (auto it = searchmapRange.first; it != searchmapRange.second; ++it) {
            NSaas::TSearchMapInputSettings settings;
            settings.Init(it->second);
            SearchMapSettings.push_back(std::move(settings));
        }
        {
            auto section = childs.find(PQ_LIB_CONFIG_LABEL);
            if (section != childs.end()) {
                InitPQLibSettings(section->second);
            }
        }
    }

    void TServerConfig::TryInitWithOldFormat(const TYandexConfig::Section* config) {
        const TYandexConfig::TSectionsMap& childs = config->GetAllChildren();
        {
            auto section = childs.find(HTTP_OPTIONS_CONFIG_LABEL);
            if (section != childs.end()) {
                ParsedFromOldFormat = true;
                const TYandexConfig::Directives& directives = section->second->GetDirectives();
                WriterConfig.HttpOptions.Init(directives);
            }
        }
        {
            auto section = childs.find(WRITER_CONFIG_LABEL);
            if (section != childs.end()) {
                ParsedFromOldFormat = true;
                WriterConfig.Init(section->second);
                InitLog(section->second);

                const TYandexConfig::TSectionsMap& writerChilds = section->second->GetAllChildren();
                auto searchmapRange = writerChilds.equal_range(SEARCHMAP_CONFIG_LABEL);
                if (searchmapRange.first == searchmapRange.second) {
                    searchmapRange = childs.equal_range(BAD_SEARCHMAP_CONFIG_LABEL);
                }
                for (auto it = searchmapRange.first; it != searchmapRange.second; ++it) {
                    NSaas::TSearchMapInputSettings settings;
                    settings.Init(it->second);
                    SearchMapSettings.push_back(std::move(settings));
                }
            }
        }
    }

    void TServerConfig::Print(IOutputStream& so) const {
        so << "LogLevel : " << (ui32)LogLevel << Endl;
        so << "Log : " << Log << Endl;
        so << "LogbrokerLog : " << LogbrokerLog << Endl;
        so << "TvmLog : " << TvmLog << Endl;

        so << "<" << PQ_LIB_CONFIG_LABEL << ">" << Endl;
        PrintPQLibSettings(so);
        so << "</" << PQ_LIB_CONFIG_LABEL << ">" << Endl;

        so << "<" << WRITER_CONFIG_LABEL << ">" << Endl;
        WriterConfig.Print(so);
        so << "</" << WRITER_CONFIG_LABEL << ">" << Endl;

        so << "UpdateSearchMapPeriod : " << UpdateSearchMapPeriod << Endl;
        PrintSections(so, SearchMapSettings, SEARCHMAP_CONFIG_LABEL);
    }

    void TServerConfig::PrintPQLibSettings(IOutputStream& so) const {
        so << "ThreadsCount : " << PQLibSettings.ThreadsCount << Endl;
        so << "CompressionPoolThreads : " << PQLibSettings.CompressionPoolThreads << Endl;
        so << "GRpcThreads : " << PQLibSettings.GRpcThreads << Endl;
        so << "ChannelCreationTimeout : " << PQLibSettings.ChannelCreationTimeout << Endl;
    }

    void TServerConfig::InitLog(const TYandexConfig::Section* config) {
        const TYandexConfig::Directives& directives = config->GetDirectives();

        ui32 logLevel = TLOG_INFO;
        directives.GetValue("LogLevel", logLevel);
        LogLevel = (ELogPriority)logLevel;

        directives.GetValue("Log", Log);
        directives.GetValue("LogbrokerLog", LogbrokerLog);
        directives.GetValue("TvmLog", TvmLog);

        DoInitGlobalLog(Log, LogLevel, false, false);
    }

    void TServerConfig::InitPQLibSettings(const TYandexConfig::Section* section) {
        const TYandexConfig::Directives& directives = section->GetDirectives();

        directives.GetValue("ThreadsCount", PQLibSettings.ThreadsCount);
        directives.GetValue("CompressionPoolThreads", PQLibSettings.CompressionPoolThreads);
        directives.GetValue("GRpcThreads", PQLibSettings.GRpcThreads);
        directives.GetValue("ChannelCreationTimeout", PQLibSettings.ChannelCreationTimeout);
    }

    void TSaasPushTelemetryConfig::Init(const TYandexConfig::Section* section) {
        NSaas::TTelemetryConfig::Init(section);
        const TYandexConfig::Directives& directives = section->GetDirectives();
        directives.GetValue("Alias", Alias);
    }

    void TSaasPushTelemetryConfig::Print(IOutputStream& so) const {
        NSaas::TTelemetryConfig::Print(so);
        so << "Alias: " << Alias << Endl;
    }

    const TString& TSaasPushTelemetryConfig::GetAlias() const {
        return Alias;
    }

    void TConfig::Init(const TYandexConfig& parsedConfig) {
        const TYandexConfig::Section* root = parsedConfig.GetRootSection();
        const TYandexConfig::TSectionsMap& childs = root->GetAllChildren();
        {
            auto section = childs.find(CONTROLLER_CONFIG_LABEL);
            if (section != childs.end()) {
                ControllerConfig.Init(section->second);
            }
        }
        {
            auto telemetrySection = childs.find(TELEMETRY_CONFIG_LABEL);
            if (telemetrySection != childs.end()) {
                TelemetryConfig.Init(telemetrySection->second);
                Y_VERIFY(TelemetryConfig.GetInterval() != TDuration::Zero(), "telemetry must be enabled: https://nda.ya.ru/t/10myAxmq3W382P");
            }
        }
        {
            auto section = childs.find(SERVER_CONFIG_LABEL);
            if (section != childs.end()) {
                ServerConfig.Init(section->second);
            }
        }

        ServerConfig.TryInitWithOldFormat(root);
    }

    void TConfig::Print(IOutputStream& so) const {
        so << "<" << CONTROLLER_CONFIG_LABEL << ">" << Endl;
        ControllerConfig.Print(so);
        so << "</" << CONTROLLER_CONFIG_LABEL << ">" << Endl;

        so << "<" << TELEMETRY_CONFIG_LABEL << ">" << Endl;
        TelemetryConfig.Print(so);
        so << "</" << TELEMETRY_CONFIG_LABEL << ">" << Endl;

        so << "<" << SERVER_CONFIG_LABEL << ">" << Endl;
        ServerConfig.Print(so);
        so << "</" << SERVER_CONFIG_LABEL << ">" << Endl;
    }
}
