#include "config.h"
#include "light_layers_registry.h"

#include <saas/rtyserver/config/const.h>
#include <saas/rtyserver/config/layers.h>
#include <saas/rtyserver/config/repair_config.h>
#include <util/string/split.h>
#include <library/cpp/mediator/global_notifications/system_status.h>

void TRTYFullArchiveConfig::TExtendedMultipartConfig::Init(const TYandexConfig::Section& section) {
    TBase::Init(section);

    LockFATFile = section.GetDirectives().Value("LockFATFile", true);

    if (LockFATFile) {
        TBase::LockFAT = true;

        AssertCorrectConfig(!TBase::PrechargeFAT, "PrechargeFAT is enabled with ThrottledLockFAT");
    }
}

void TRTYFullArchiveConfig::TExtendedMultipartConfig::Check() const {
    TBase::Check();
}

void TRTYFullArchiveConfig::TExtendedMultipartConfig::ToString(IOutputStream& so) const {
    TBase::ToString(so);

    so << "LockFATFile: " << LockFATFile << Endl;
}

TString TRTYFullArchiveConfig::TExtendedMultipartConfig::ToString(const char* sectionName) const {
    TStringStream so;
    so << "<" << sectionName << ">" << Endl;
    ToString(so);
    so << "</" << sectionName << ">" << Endl;
    return so.Str();
}

bool TRTYFullArchiveConfig::DoCheck() const {
    return true;
}

void TRTYFullArchiveConfig::DoInit(const TYandexConfig::Section& componentSection) {
    // Note: the method is not called when FULLARC has no configuration
    // If you change the defaults here, please change them in the constructor, and in the header too.

    const TRTYServerConfig& globalConfig = Owner->GetMeAs<TRTYServerConfig>();
    TYandexConfig::TSectionsMap children = componentSection.GetAllChildren();
    TYandexConfig::TSectionsMap::const_iterator def = children.find("DefaultLayerConfig");
    if (def != children.end())
        DefaultLayerConfig.Init(*def->second);
    else
        DefaultLayerConfig.Init(componentSection);

    auto range = children.equal_range("Layers");
    for (; range.first != range.second; ++range.first) {
        TYandexConfig::TSectionsMap layers = range.first->second->GetAllChildren();
        for (const auto& layer : layers) {
            auto inserted = Layers.insert(std::make_pair(layer.first, DefaultLayerConfig));
            if (!inserted.second)
                ythrow yexception() << "Layer " << layer.first << " already defined";
            inserted.first->second.Init(*layer.second);
        }
    }
    if (globalConfig.IndexGenerator != FULL_ARCHIVE_COMPONENT_NAME && !Layers.contains(NRTYServer::NFullArchive::BaseLayer)) {
        auto inserted = Layers.insert(std::make_pair(NRTYServer::NFullArchive::BaseLayer, DefaultLayerConfig));
        CHECK_WITH_LOG(inserted.second);
        inserted.first->second.PartSizeLimit -= 1;
    }

    DisablePartsOptimization = componentSection.GetDirectives().Value("DisablePartsOptimization", false);
    NoFullLayer = componentSection.GetDirectives().Value("NoFullLayer", false);

    MainLayer = componentSection.GetDirectives().Value("MainLayer", NRTYServer::NFullArchive::BaseLayer);

    ActiveLayersFinal.clear();

    {
        const TString& activeLayersString = componentSection.GetDirectives().Value("ActiveLayers", TString());
        TVector<TString> splitted = StringSplitter(activeLayersString).SplitBySet(", ").SkipEmpty();
        ActiveLayersFinal.insert(std::make_move_iterator(splitted.begin()), std::make_move_iterator(splitted.end()));
    }

    {
        const TString& lightLayersString = componentSection.GetDirectives().Value("LightLayers", TString());
        TVector<TString> splitted = StringSplitter(lightLayersString).SplitBySet(", ").SkipEmpty();
        LightLayersConfig.insert(splitted.begin(), splitted.end()); // this value should be used only for ToString
        for (const auto& layer : splitted) {
            if (!TLightLayersRegistry::Instance()->IsLightLayer(layer)) {
                ERROR_LOG << "No L2 component is registered for light layer: " << layer << Endl;
                continue;
            }
            ActiveLayersFinal.insert(layer);
        }
    }

    if (!NoFullLayer && ActiveLayersFinal.empty()) {
        ActiveLayersFinal.insert(NRTYServer::NFullArchive::FullLayer);
    }
    ActiveLayersFinal.insert(MainLayer);
    if (!NoFullLayer && globalConfig.IndexGenerator == FULL_ARCHIVE_COMPONENT_NAME) {
        ActiveLayersFinal.insert(NRTYServer::NFullArchive::FullLayer);
    }

    ActiveLayersTemp = ActiveLayersFinal;
    if (globalConfig.GetRepairConfig().Enabled) {
        ActiveLayersTemp.insert(NRTYServer::NFullArchive::FullLayer);
    }
}

void TRTYFullArchiveConfig::DoToString(IOutputStream& so) const {
    so << "ActiveLayers: " << JoinStrings(ActiveLayersFinal.begin(), ActiveLayersFinal.end(), ", ") << Endl;
    so << "LightLayers: " << JoinStrings(LightLayersConfig.begin(), LightLayersConfig.end(), ", ") << Endl;
    so << "DisablePartsOptimization: " << DisablePartsOptimization << Endl;
    so << "NoFullLayer: " << NoFullLayer << Endl;
    so << "<Layers>" << Endl;
    for (const auto& layer : Layers) {
        so << "<" << layer.first << ">" << Endl;
        layer.second.ToString(so);
        so << "</" << layer.first << ">" << Endl;
    }
    so << "</Layers>" << Endl;
    so << "<DefaultLayerConfig>" << Endl;
    DefaultLayerConfig.ToString(so);
    so << "</DefaultLayerConfig>" << Endl;
}

TRTYFullArchiveConfig::TRTYFullArchiveConfig() {
    DefaultLayerConfig.Compression = NRTYArchive::IArchivePart::COMPRESSED;
    ActiveLayersFinal.insert(NRTYServer::NFullArchive::BaseLayer);
    ActiveLayersTemp.insert(NRTYServer::NFullArchive::BaseLayer);
    ActiveLayersTemp.insert(NRTYServer::NFullArchive::FullLayer);
}

const TRTYFullArchiveConfig::TExtendedMultipartConfig& TRTYFullArchiveConfig::GetLayer(const TString& name) const {
    TLayers::const_iterator i = Layers.find(name);
    if (i == Layers.end())
        return DefaultLayerConfig;
    return i->second;
}
