#include "rty_index_data.h"
#include "rty_relevance.h"
#include "rty_index_text_data.h"

#include <saas/rtyserver/factors/function.h>
#include <saas/rtyserver/components/generator/manager.h>
#include <saas/rtyserver/components/erf/erf_component.h>
#include <saas/rtyserver/components/zones_makeup/makeup_component.h>
#include <saas/rtyserver/components/zones_makeup/makeup_manager.h>
#include <saas/rtyserver/components/qs/qs_component.h>
#include <saas/rtyserver/components/cs/cs_component.h>
#include <saas/rtyserver/components/cs/cs_manager.h>
#include <saas/rtyserver/components/qs/qs_manager.h>
#include <saas/rtyserver/components/fastarchive/manager.h>
#include <saas/rtyserver/components/fastarchive/globals.h>
#include <saas/rtyserver/components/ann/manager.h>
#include <saas/rtyserver/components/ann/config.h>
#include <saas/rtyserver/components/ann/const.h>
#include <saas/rtyserver/components/prop/globals.h>
#include <saas/rtyserver/components/prop/manager.h>

#include <kernel/externalrelev/relev.h>

struct TRTYIndexData::TIndexDataDetails {
    THolder<NIndexAnn::TReaders> ExternalFactorAnnReaders;
};

class TRTYIndexDynamicData : public TBaseIndexDynamicData {
public:
    TRTYIndexDynamicData(const TSearchConfig& config, 
            const TBaseIndexDataOptions& options, 
            const TAnnIndexManager* annManager,
            TRTYIndexData::TIndexDataDetails& rtyBid)
        : TBaseIndexDynamicData(config, options)
    {
        NIndexAnn::TReadersOpts opts(options.IndexName + "ann.");
        opts.CreateSent = true;
        if (annManager->HasType("ann")) {
            AnnReaders.Reset(new NIndexAnn::TReaders(opts));
            AnnReaders->SetDocDataIndex(new TRTYAnnReader(annManager, "ann"));
        }

        if (annManager->HasType("factorann")) {
            opts.IndexPrefix = options.IndexName + "factorann.";

            rtyBid.ExternalFactorAnnReaders.Reset(new NIndexAnn::TReaders(opts));
            rtyBid.ExternalFactorAnnReaders->SetDocDataIndex(new TRTYAnnReader(annManager, "factorann"));

            const bool replaceFactorAnn = annManager->GetConfig().UseExternalCalcer;
            if (!replaceFactorAnn) {
                // enables old way of FactorAnn calculation
                FactorAnnReaders.Swap(rtyBid.ExternalFactorAnnReaders);
                rtyBid.ExternalFactorAnnReaders.Destroy();
            }
        }
    }
};


namespace {
    THolder<TRTYIndexTextData> CreateIndexTextData(const IMakeupStorage* makeup, const NRTYServer::TSearcherConfig* rtySearcherConfig) {
        Y_VERIFY(!!rtySearcherConfig);

        TRTYIndexTextData::TData textOpts;
        textOpts.AutoTitleSentNum = rtySearcherConfig->TextMachine.TitleSentencesNumber;
        textOpts.Makeup = makeup;

        return MakeHolder<TRTYIndexTextData>(std::move(textOpts));
    }

    THolder<NRTYFeatures::TImportedFunctions> CreateImportedFunctions(const NRTYServer::IIndexComponentManager* indexManager) {
        if (indexManager != nullptr) {
            // happens only when INDEX component is present
            return MakeHolder<NRTYFeatures::TImportedFunctions>();
        } else {
            return THolder<NRTYFeatures::TImportedFunctions>();
        }
    }
}

TRTYIndexData::TRTYIndexData(IIndexController::TPtr index,
                             const NRTYServer::TSearcherConfig* rtySearcherConfig,
                             const IDocLenCalcer* docLenCalcer)
    : IndexController(index)
    , RTYIndexManager(GetManager<NRTYServer::IRTYIndexManager>(rtySearcherConfig->Owner.IndexGenerator))
    , RTYErfManager(GetManager<IRTYErfManager>(ERF_COMPONENT_NAME))
    , MakeupManager(GetManager<TRTYMakeupManager>(MAKEUP_COMPONENT_NAME))
    , FastArchiveManager(GetManager<TRTYFastArchiveManager>(FASTARCHIVE_COMPONENT_NAME))
    , QSManager(GetManager<TQSManager>(QS_COMPONENT_NAME))
    , CSManager(GetManager<TCSManager>(CS_COMPONENT_NAME))
    , DDKManager(index->GetDDKManager())
    , AnnIndexManager(GetManager<TAnnIndexManager>(NRTYServer::AnnComponentName))
    , RTYSearcherConfig(rtySearcherConfig)
    , DocsAttrs(nullptr)
    , DocLenCalcer(docLenCalcer)
    , PropManager(GetManager<NRTYServer::IPropManager>(TString{NRTYServer::PropComponentName}))
    , IndexDataDetails(MakeHolder<TIndexDataDetails>())
    , IndexTextOpts(CreateIndexTextData(MakeupManager, rtySearcherConfig))
    , ImportedFunctions(CreateImportedFunctions(GetManager<TBaseIndexManager>(INDEX_COMPONENT_NAME)))
{}

TRTYIndexData::~TRTYIndexData() {
}

void TRTYIndexData::SetIndexDataOptions(TBaseIndexDataOptions& options) const {
    options.IsLinkPolite = true;
    options.HasQuorumData = RTYSearcherConfig->FiltrationModel == NRTYServer::TSearcherConfig::fmWeb;
    options.ExternalIndexAnn = AnnIndexManager && AnnIndexManager->HasType("ann");
    options.ExternalFactorAnn = AnnIndexManager && AnnIndexManager->HasType("factorann");
    if (options.ExternalFactorAnn) {
        options.OldFactorAnnHitsLimit = AnnIndexManager->GetFactorAnnHitsLimit();
    }
    options.ExternalTfManager = true;
}

const ISentenceZonesReader* TRTYIndexData::GetMakeupReader() const {
    return GetMakeupManager();
}

const NIndexAnn::TReaders* TRTYIndexData::GetFactorAnnReaders(const TBaseIndexData& bid) const {
    if (IndexDataDetails->ExternalFactorAnnReaders) {
        Y_ASSERT(bid.GetFactorAnnReaders() == nullptr);
        return IndexDataDetails->ExternalFactorAnnReaders.Get();
    } else {
        return bid.GetFactorAnnReaders();
    }
}

TBaseIndexDynamicData* TRTYIndexData::CreateBaseIndexDynamicData(const TSearchConfig& config, const TBaseIndexDataOptions& options) {
    if (AnnIndexManager) {
        return new TRTYIndexDynamicData(config, options, AnnIndexManager, *IndexDataDetails);
    }
    return nullptr;
}

