#pragma once

#include "parsed_entity.h"

#include <saas/rtyserver/factors/factors_config.h>
#include <saas/rtyserver/factors/rank_model.h>
#include <saas/rtyserver/search/gators/bm25levels.h>
#include <kernel/factor_storage/factor_storage.h>
#include <util/generic/singleton.h>
#include <util/generic/vector.h>

class TSuggestFactorsCalcer {
public:
    struct THits {
        inline THits()
            : Begin(nullptr)
            , End(nullptr)
        {}

        const TFullPositionEx* Begin;
        const TFullPositionEx* End;
    };
    typedef float (TSuggestFactorsCalcer::* TFactorCalcer)(const TSuggestRecord& sr, const THits& hits);

    class TAvailableFactors : public THashMap<TString, TFactorCalcer>{
        Y_DECLARE_SINGLETON_FRIEND()
    public:
        static const TAvailableFactors& Instance();
    private:
        TAvailableFactors();
    };

public:
    void Init(const TRTYServerConfig& config, const NRTYFactors::TRankModelHolder& rankModel, ui32 queryWordsCount);

    inline void CalcFactors(TFactorStorage& storage, const TSuggestRecord& sr, const THits& hits) {
        for (const TFactorData& factor : Factors)
            storage.factors[factor.Index] = (this->*factor.Calcer)(sr, hits);
    }

private:
    struct TFactorData {
        TFactorData(ui32 index, TFactorCalcer calcer)
            : Index(index)
            , Calcer(calcer)
        {}

        ui32 Index;
        TFactorCalcer Calcer;
    };

private:
    float CalcCountFactor(const TSuggestRecord& sr, const THits& hits);
    float CalcAverageWeightFactor(const TSuggestRecord& sr, const THits& hits);
    float CalcWordsCountFactor(const TSuggestRecord& sr, const THits& hits);
    float CalcFirstWordPositionInvFactor(const TSuggestRecord& sr, const THits& hits);
    float CalcBM25Factor(const TSuggestRecord& sr, const THits& hits);
    float CalcOrderFactor(const TSuggestRecord& sr, const THits& hits);
    float CalcDensityFactor(const TSuggestRecord& sr, const THits& hits);

private:
    TVector<TFactorData> Factors;
    TBm25LevelsTracker Bm25Tracker;
    TVector<float> WordWeight;
    ui32 MaxSuggestLength;
};
