#include "sln_normalizer.h"

#include <saas/rtyserver/components/generator/manager.h>
#include <saas/rtyserver/components/oxy/processors/tuples_list.h>

#include <robot/library/oxygen/indexer/processor/createprocessors/createprocessors.h>
#include <robot/library/oxygen/indexer/processor/processor/processor.h>
#include <robot/library/oxygen/indexer/object_context/object_context.h>
#include <robot/library/oxygen/indexer/processor/protos/config.pb.h>

#include <search/pruning/file/suffix.h>
#include <util/system/fs.h>


TOXYSlnNormalizer::TOXYSlnNormalizer(const TRTYServerConfig& config, const THolder<TTuplesListsAndFilters>& tuplesListsAndFilters)
    : NRTYServer::TOxygenNormalizer(config)
    , TuplesListsAndFilters(tuplesListsAndFilters)
{}

const char* TOXYSlnNormalizer::Name() const {
    return "OXYSlnNormalizer";
}

bool TOXYSlnNormalizer::AllRight(const NRTYServer::TNormalizerContext& context, const THolder<TFileMap>& /* indexFrq */) const {
    NOxygen::TTuplesListProcessor::TTupleNameSetByLayers savedTuples;
    if (!NOxygen::TTuplesListProcessor::LoadTuplesList(context.Dir.PathName(), savedTuples))
        return true;

    if (!context.Managers.GetIndexManager()->GetSearchableDocumentsCount())
        return true;

    NOxygen::TTupleNameSet savedLayer;

    if (savedTuples.contains(TuplesListsAndFilters->GetLayerForMerge())) {
        savedLayer = savedTuples[TuplesListsAndFilters->GetLayerForMerge()];
    } else {
        savedLayer = savedTuples[NRTYServer::NFullArchive::FullLayer];
    }

#if 0
    for (const auto& i : TuplesListsAndFilters->GetNecessaryTuples(true)) {
        AssertCorrectIndex(savedLayer.has(i), "There is no required %s tuple in %s", ~i, ~context.Dir.PathName());
    }
#endif
    const NOxygen::TOxygenOptions* oxygenOptions = GetOxygenOptions(context);
    AssertCorrectConfig(oxygenOptions, "OxygenOptions are missing");
    AssertCorrectIndex(TFsPath(context.Dir.PathName() + "/indexfrq").Exists(), "not found indexfrq for %s", context.Dir.PathName().data());

    if (HasPruning(oxygenOptions)) {
        if (!TFsPath(context.Dir.PathName() + "/index" + NPruningData::SELECTION_SUFFIX).Exists()) {
            return false;
        } else {
            TFileMap fmSln(context.Dir.PathName() + "/index" + NPruningData::SELECTION_SUFFIX);
            TFileMap fmFrq(context.Dir.PathName() + "/indexfrq");
            if (fmSln.Length() / sizeof(float) != fmFrq.Length() / sizeof(ui16)) {
                TString filePath = context.Dir.PathName() + "/index" + NPruningData::SELECTION_SUFFIX;
                NFs::Remove(filePath);
                return false;
            }
        }
    }
    return true;
}

void TOXYSlnNormalizer::Fix(const NRTYServer::TNormalizerContext& context, const THolder<TFileMap>& /* indexFrq */) const {
    const NOxygen::TOxygenOptions* oxygenOptions = GetOxygenOptions(context);
    AssertCorrectConfig(oxygenOptions, "OxygenOptions are missing");
    const TString dir = context.Dir.PathName();
    if (!TFsPath(dir + "/index" + NPruningData::SELECTION_SUFFIX).Exists() && HasPruning(oxygenOptions)) {
        AssertCorrectIndex(TFsPath(dir + "/index" + NPruningData::SUFFIX).Exists(), "Incorrect indexprn for %s", dir.data());
        AssertCorrectIndex(TFsPath(dir + "/indexfrq").Exists(), "Incorrect indexprn for %s", dir.data());
        ui32 prnLength = TFile(dir + "/index" + NPruningData::SUFFIX, RdOnly).GetLength();
        ui32 frqLength = TFile(dir + "/indexfrq", RdOnly).GetLength();

        ui32 mapSize = Min(frqLength, prnLength);

        AssertCorrectIndex(mapSize % 2 == 0, "Incorrect indexprn size for %s", dir.data());

        TFileMappedArray<ui16> prnArr;
        prnArr.Init(dir + "/index" + NPruningData::SUFFIX);

        TUnbufferedFileOutput fo(dir + "/index" + NPruningData::SELECTION_SUFFIX);
        for (ui32 i = 0; i < mapSize / 2; ++i) {
            float value = prnArr[i];
            fo.Write(&value, sizeof(value));
        }
        fo.Finish();
        AssertCorrectIndex(TFsPath(context.Dir.PathName() + "/index" + NPruningData::SELECTION_SUFFIX).Exists(), "Can't restore indexsln");
    }
}

bool TOXYSlnNormalizer::HasPruning(const NOxygen::TOxygenOptions* oxygenOptions) const {
    if (oxygenOptions) {
        return oxygenOptions->GetSorter().HasPruning() || oxygenOptions->GetRTYProcessorOptions().HasMixerOptions();
    } else {
        return false;
    }
}
