#include "makeup_builder.h"
#include "makeup_component.h"
#include "makeup_parsed_entity.h"

#include <saas/rtyserver/config/common_indexers_config.h>
#include <saas/rtyserver/indexer_core/abstract_model.h>

using namespace NZonesMakeup;

namespace {
    class TMakeupSaverCleanupGuard : public TMoveOnly {
    private:
        TMakeupSaver& Saver;
    public:
        explicit TMakeupSaverCleanupGuard(TMakeupSaver& saver)
            : Saver(saver)
        {}

        ~TMakeupSaverCleanupGuard() {
            Saver.Reset();
        }
    };
}

void TRTYMakeupBuilder::InitInteractions(const NRTYServer::IIndexBuildersStorage& storage) {
    NRTYServer::IDTIndexBuilder* indexBuilder = storage.GetBuilder<NRTYServer::IDTIndexBuilder>(INDEX_COMPONENT_NAME);
    if (indexBuilder) {
        CHECK_EQ_WITH_LOG(Savers.size(), 0);
        for (size_t i = 0; i < IndexerConfig.Threads; i++) {
            Savers.push_back(MakeHolder<TMakeupSaver>(this, Config.IsPrefixedIndex));
            Savers.back()->Reset();
        }
        TVector<IYndexStorage*> storages;
        storages.reserve(IndexerConfig.Threads);
        for (size_t i = 0; i < IndexerConfig.Threads; i++) {
            storages.push_back(Savers[i]->GetAttrIFace());
        }
        indexBuilder->RegisterStoragesAttr(storages);
        storages.clear();
        for (size_t i = 0; i < IndexerConfig.Threads; i++) {
            storages.push_back(Savers[i]->GetLemmIFace());
        }
        indexBuilder->RegisterStoragesLemm(storages);
    }
}

TRTYMakeupBuilder::TRTYMakeupBuilder(ui32 countDocs, const NRTYServer::TIndexerConfig& config, bool useMemPool, bool isMem, const TString& componentName)
    : NRTYServer::IIndexComponentBuilder(componentName)
    , Config(config.Common.Owner)
    , IndexerConfig(config)
{
    Manager = new TReadWriteRTYMakeupManager(countDocs, config.Common.Owner, config.GetType() == "memory", useMemPool, isMem);
}

void TRTYMakeupBuilder::Index(int threadID, const TParsedDocument& document, const ui32 docId) {
    VERIFY_WITH_LOG(!!Manager, "Incorrect manager entry for makeup builder");
    const TRTYMakeupParsedEntity* docMakeup = document.GetComponentEntity<TRTYMakeupParsedEntity>(MAKEUP_COMPONENT_NAME);
    VERIFY_WITH_LOG(docMakeup, "There is no makeup data for %s", document.GetDocSearchInfo().GetUrl().data());
    TMaybe<TMakeupSaverCleanupGuard> cleanupGuardMaybe;
    if (Savers.size() > (ui32)threadID) {
        cleanupGuardMaybe.ConstructInPlace(*Savers[threadID].Get());
    }
    if (docMakeup->HasMakeup()) {
        TStringInput in(docMakeup->GetMakeup());
        Manager->DeserializeDocument(docId, in);
    } else {
        VERIFY_WITH_LOG((int)Savers.size() > threadID, "Incorrect savers for makeup index: %d (index) >= %lu (count)", threadID, Savers.size());
        Savers[threadID]->Finish(docId);
        docMakeup->MutableMakeup().clear();
        TStringOutput out(docMakeup->MutableMakeup());
        Manager->SerializeDocument(docId, out);
    }
}

bool TRTYMemoryMakeupBuilder::DoClose(const NRTYServer::TBuilderCloseContext& context) {
    VERIFY_WITH_LOG(context.SrcDir == context.DstDir, "Not supported");
    return true;
}

bool TRTYDiskMakeupBuilder::DoClose(const NRTYServer::TBuilderCloseContext& context) {
    if (!!context.RigidStopSignal && *context.RigidStopSignal)
        return true;
    VERIFY_WITH_LOG(context.SrcDir == context.DstDir, "Not supported");
    if (!!Manager) {
        TFixedBufferFileOutput hdrBfo(context.SrcDir.PathName() + TRTYMakeupManager::HdrFileName);
        TFixedBufferFileOutput docsBfo(context.SrcDir.PathName() + TRTYMakeupManager::DocsFileName);
        Manager->Serialize(hdrBfo, docsBfo, context.RemapTable);
    }
    return true;
}
