#include "normalizer.h"
#include "processor.h"

#include <saas/rtyserver/components/fullarchive/disk_manager.h>
#include <saas/util/queue.h>

#include <robot/library/oxygen/base/protobuf/pb_utils.h>
#include <robot/library/oxygen/indexer/idspace/docid.h>

const char* TPantherNormalizer::Name() const {
    return "PantherNormalizer";
}

bool TPantherNormalizer::AllRight(const NRTYServer::TNormalizerContext& context, const THolder<TFileMap>& /*indexFrq*/) const {
    const NOxygen::TOxygenOptions* oxygenOptions = GetOxygenOptions(context);
    AssertCorrectConfig(oxygenOptions, "OxygenOptions are required for Panther normalizer");
    if (!oxygenOptions->GetRTYProcessorOptions().HasPantherOptions()) {
        return true;
    }

    const TFsPath directory = context.Dir.PathName();
    return NFs::Exists(directory / "indexcounts.key") && NFs::Exists(directory / "indexcounts.inv");
}

void TPantherNormalizer::Fix(const NRTYServer::TNormalizerContext& context, const THolder<TFileMap>& /*indexFrq*/) const {
    const auto archive = context.Managers.GetManager<TDiskFAManager>(FULL_ARCHIVE_COMPONENT_NAME);
    const TFsPath directory = context.Dir.PathName();
    const NOxygen::TOxygenOptions* oxygenOptions = GetOxygenOptions(context);
    AssertCorrectConfig(oxygenOptions, "OxygenOptions are required for Panther normalizer");
    AssertCorrectConfig(archive, "FullArchive is required to restore Panther");
    AssertCorrectIndex(archive->IsOpened(), "FullArchive must be opened to restore Panther");

    INFO_LOG << "Restoring Panther in " << directory.Basename() << Endl;
    TAtomicSharedPtr<IThreadPool> queue = CreateRTYQueue(1, 0, NUtil::TSmartMtpQueue::TOptions::GetNoBallocOptions().SetThreadName("PantherNorm"));
    NRTYServer::TPantherProcessor panther(directory, directory, oxygenOptions->GetRTYProcessorOptions().GetPantherOptions(), queue);
    panther.Start();

    ui32 docId = 0;
    NOxygen::TDocIdMap remap;
    for (auto iterator = archive->CreateIterator(); iterator->IsValid(); iterator->Next()) {
        const ui32 realDocId = iterator->GetDocId();
        if (archive->IsRemoved(realDocId)) {
            continue;
        }

        const NRTYServer::TParsedDoc& pd = iterator->GetParsedDoc();

        NOxygen::TObjectContext objectContext(pd.GetDocument().GetIndexedDoc().GetKiwiObject());
        NOxygen::TReturnObjectContext result = panther.Process(objectContext, docId).GetValue(TDuration::Max());
        AssertCorrectIndex(result.IsProcessedOk(), "Cannot restore Panther: %s", NOxygen::WritePbText(result.GetErrors()).data());
        remap.SetMapValue(docId++, realDocId);
    }

    panther.Finish(&remap);
    INFO_LOG << "Restored Panther in " << directory.Basename() << Endl;
}
