#pragma once

#include "factors_mask.h"
#include "ranking_pass.h"
#include "rty_index_data.h"
#include "rty_features.h"

#include <saas/rtyserver/search/cgi/rty_external_cgi.h>
#include <saas/rtyserver/search/cgi/rty_ranking_opts.h>
#include <saas/rtyserver/factors/factors_config.h>
#include <saas/rtyserver/factors/factors_mask.h>
#include <saas/rtyserver/factors/user_factors_calcer.h>
#include <saas/rtyserver/components/qs/qs_manager.h>
#include <saas/rtyserver/components/ann/manager.h>

class TZoneGator;
class TTextMachineFeaturesCalcer;
class TRTYQuorumAnnFeaturesCalcer;

namespace NRTYFactors {
    class IUserRanking;
}

class TFactorsCalcer : public IFactorsInfo {
public:
    TFactorsCalcer(
        TZoneGator*& zoneGator,
        const NRTYFactors::TRankModelHolder& formula,
        const TFactorsMaskCache& factorsMaskCache,
        const TRTYRankingPassContext* rankingPass,
        const TRTYIndexData* indexData,
        const IRTYCgiReader* cgi,
        const bool fastFeaturesOnly);

    void OnBeforePass();
    void OnReopenTextMachine();
    void CalcFactors(TCalcFactorsContext& ctx);
    void CalcNoUserFactors(TCalcFactorsContext& ctx);
    void CalcUserFactors(TCalcFactorsContext& ctx);

    virtual size_t GetFactorCount() const;
    virtual bool GetFactorIndex(const char* name, size_t* index) const;
    virtual const char* GetFactorName(size_t index) const;
    virtual const char* const* GetFactorNames() const;
    virtual bool IsUnusedFactor(size_t index) const;

    inline const NRTYFactors::TUsedFactors& GetUsedFactors() const {
        return UsedFactors;
    }

    inline const TCombinedFactorMask& GetFactorMask() const {
        Y_ASSERT(FactorMasks);
        return FactorMasks->DynamicMask;
    }

    inline const NRTYFactors::TFactorChunks& GetFactorChunks() const {
        Y_ASSERT(FactorMasks);
        return FactorMasks->DynamicChunks;
    }

    inline const NRTYFactors::TRTYFactorMask& GetRTYFactorMask() const {
        return *GetRTYFactorMaskPtr();
    }

    inline const NRTYFactors::TRTYFactorMask* GetRTYFactorMaskPtr() const {
        Y_ASSERT(FactorMasks);
        return &FactorMasks->RTYMask;
    }

    inline void FillDynamicContext(TRTYDynamicFeatureContext& ctx) const {
        Y_ASSERT(Cgi);
        Cgi->FillDynamicContext(ctx);
    }

    bool UsesWebProductionCalcer() const;

    const NRTYFactors::TUserDefinedAttrsStorage* GetUserDefinedAttrs() const {
        if (UserFactorsCalcer) {
            return UserFactorsCalcer->GetUserDefinedAttrs();
        }
        return nullptr;
    }

private:
    template<bool all>
    void InitSpecialFactors(ui32 docId);
    template<bool all>
    void InitRTYFactors(TFactorStorage& factorStorage, ui32 docId);
    void CalcRefineFactor(TCalcFactorsContext& ctx);

private:
    const NRTYFactors::TConfig& Config;

    TZoneGator*& ZoneGator;
    const TQSManager* QS;
    const TCSManager* CS;
    const IRTYErfManager* Erf;
    const IDocLenCalcer* DocLen;
    const IDDKManager* DDK;
    const TAnnIndexManager* Ann;
    const IRTYCgiReader* Cgi;
    const TRTYRankingPassContext& RankingPass;
    NRTYFeatures::IFeatureCalcer::TPtr DP;
    THolder<NRTYFactors::TUserFactorsCalcer::TFormulaUserFactorsCalcer> UserFactorsCalcer;
    TAtomicSharedPtr<NRTYFactors::IUserRanking> UserCalcer;
    TQSIteratorsPull::TPtr QSItPull;
    TFactorStorage FactorStorage;

    NRTYFactors::TUsedFactors UsedFactors;
    const NRTYServer::TFactorMasks* FactorMasks;
};
