#include "index_manager.h"
#include <saas/rtyserver/config/config.h>
#include <saas/rtyserver/factors/function.h>
#include <saas/rtyserver/search/external_search/rty_index_data.h> // TBaseIndexManager includes this too
#include <search/base/yx_search.h>

TRTYIndexManager::TRTYIndexManager(const NRTYServer::TManagerConstructionContext& context, const TString& componentName)
    : TBaseIndexManager(context, componentName)
{
}

bool TRTYIndexManager::UpdateDoc(ui32 docId, const TParsedDocument::TPtr doc) {
    NGroupingAttrs::TDocsAttrs* mutableDocsAttrs = Index.GetGroupsAttrs();
    if (!mutableDocsAttrs) {
        ERROR_LOG << "status=document_updating;error=docsattrs_must_be_created" << Endl;
        return false;
    }

    const TIndexParsedEntity* docIndex = doc->GetComponentEntity<TIndexParsedEntity>(ComponentName);
    VERIFY_WITH_LOG(docIndex, "Cannot update GroupAttributes without INDEX COMPONENT");

    const NGroupingAttrs::TConfig& config = mutableDocsAttrs->Config();

    bool result = false;
    for (NRTYServer::TAttrs::const_iterator i = docIndex->GetGroupingAttributes().begin(); i != docIndex->GetGroupingAttributes().end(); ++i) {
        TRY
            const TString& name = i->first;
            const ui32 num = config.AttrNum(name.data());
            if (num == NGroupingAttrs::TConfig::NotFound || !config.IsAttrUnique(num)) {
                WARNING_LOG << "Cannot update group attribute " << name << " in " << IndexDir.BaseName() << " docId " << docId << Endl;
                continue;
            }

            TCateg value = 0;
            if (!mutableDocsAttrs->DocCateg(docId, num, value))
                ythrow yexception() << "invalid attr value";
            value = NRTYServer::TAttr::GetUpdateValue<TCateg>(value, i->second.Values[0], i->second.Action);
            if (!mutableDocsAttrs->SetDocCateg(docId, num, value))
                ythrow yexception() << "invalid attr value";
            result = true;
        CATCH("Url = " +  doc->GetDocSearchInfo().GetUrl() + "attr = " + i->first)
    }
    return result;
}

namespace {
    void LinkImports(NRTYFeatures::TImportedFunctions& imports, const IIndexController& owner, const NRTYFactors::TConfig& relevConf) {
        NRTYFeatures::TImportedFunctionsBuilder builder(imports);
        TSet<TString> alienComponents;
        for (auto&& [importName, componentName]: relevConf.GetUserFunctions()) {
            alienComponents.insert(componentName);
            builder.Request(importName);
        }
        for (auto&& componentName: alienComponents) {
            const NRTYServer::IIndexComponentManager* component = owner.GetManager(componentName);
            if (!component)
                continue;
            component->GetExportedFunctions(builder);
        }
    }
}

void TRTYIndexManager::LinkIndexData(IRemapperUrlDocId& remapper, TRTYIndexData* indexData) const {
    TBaseIndexManager::LinkIndexData(remapper, indexData);
    const NRTYFactors::TConfig& relevConf = *Config.GetSearcherConfig().Factors;
    if (relevConf.NeedDocsLens())
        DocsLens = MakeHolder<TDocsLens>(BaseSearch->BaseIndexData->GetTextYR()->YMain(), YDX_DOC_LEN_KEY, GetDocumentsCount());
    if (NRTYFeatures::TImportedFunctions* imports = indexData->GetImportedFunctions())
        LinkImports(*imports, *indexData->GetIndexController(), relevConf);
}

void TRTYIndexManager::UnlinkIndexData() const {
    TBaseIndexManager::UnlinkIndexData();
    DocsLens.Destroy();
}

ui32 TRTYIndexManager::GetDocLen(ui32 docid) const {
    Y_ASSERT(DocsLens);
    return DocsLens->GetAt(docid);
}
