#pragma once

#include "rty_search_statistics.h"

#include <saas/rtyserver/common/common_rty.h>
#include <saas/rtyserver/config/fwd.h>
#include <saas/rtyserver/factors/user_factors_calcer.h>
#include <saas/rtyserver/search/processors/processor.h>
#include <saas/rtyserver/components/qs/functions/qs_function_abstract.h>
#include <saas/rtyserver/search/context/rty_search_context.h>

#include <search/reqparam/reqparam.h>

#include <util/generic/string.h>
#include <util/generic/map.h>

class IArchiveData;
class ISentenceZonesReader;
class IFastArchive;
class IRTYDocProcessor;
class TRTYIndexData;
class TRTYIndexTextData;

namespace NRTYFactors {
    class TUserFactorsCalcer;
}

//
// Context for IDocProcessor and dynamic factors calculation
//
struct TRTYDynamicFeatureContext {
    const TRequestParams* RP = nullptr;
    const IArchiveData* AD = nullptr;
    const TRTYIndexTextData* TD = nullptr;
    const ISentenceZonesReader* Makeup = nullptr;
};

//
// EFilterBorderMode: selects a style in with the FilterBorder (a threshold of relevance) is applied (SAAS-5538)
//
enum class EFilterBorderMode {
    Default = 0,
    MatrixNetOnly
};

enum class ECalcFactors {
    Formula = 0,
    LightAndFormula = 1,
    All,
};

class IRTYCgiReader : public ICustomCgi, public IQSRequest {
public:
    using TExtraFactors = TVector<ui32>;

public:
    virtual const NRTYFactors::TRankModelHolder* GetFilterModel() const = 0;
    virtual const NRTYFactors::TRankModelHolder* GetFastFilterModel() const = 0;
    virtual const NRTYFactors::TRankModelHolder* GetRankModel() const = 0;
    virtual const NRTYFactors::TRankModelHolder* GetFastRankModel() const = 0;
    virtual const NRTYFactors::TUserFactorsCalcer* GetUserFactorsCalcer() const = 0;
    virtual const TExtraFactors* GetExtraFactors(bool fastRank) const = 0;
    virtual const TString* GetNamedFactorSet(bool fastRank) const = 0;
    virtual IRTYDocProcessor* GetRtyDocProcessor() const = 0;
    virtual TComponentSearcher* GetPreSearcher() const = 0;
    virtual ECalcFactors CalcAllFactors(bool fastrank) const = 0;
    virtual bool ShouldCalcAllStaticFactors() const = 0;
    virtual bool ShouldUseExternalAnnCalcer() const = 0;
    virtual bool IsQuorumAnnDisabled(bool rtyAnnSaas) const = 0;

    virtual float GetFilterBorder() const = 0;
    virtual float GetFastFilterBorder() const = 0;
    virtual EFilterBorderMode GetFbMode() const = 0;
    virtual EFilterBorderMode GetFastFbMode() const = 0;
    virtual bool GetBorderKeepRefineDoc() const = 0;
    virtual TVector<ui64> GetKps() const = 0;
    virtual TMaybe<TString> GetTmName() const = 0;
    virtual void FillDynamicContext(TRTYDynamicFeatureContext& ctx) const = 0;
    virtual TMaybe<bool> ShouldImitateQrQuorum() const = 0;
    virtual bool IsSoftnessEnabledInTextQuorum() const = 0;
    virtual bool AreRtyFactorsRequested() const = 0;
    virtual ui32 GetFactorAnnHitsLimit() const = 0;
};


class TRTYCgiReader : public IRTYCgiReader {
private:
    const TRTYIndexData& IndexData;

    const IArchiveData* AD;
    const IFastArchive* FastArchive;
    TDocProcessors DocProcessors;
    TAtomicSharedPtr<IRTYDocProcessor> RtyDocProcessor;
    TComponentSearcher::TPtr ComponentSearcher = nullptr;

    const IRemapperUrlDocId& Remapper;
    const NRTYFactors::TConfig* Factors;
    const NRTYFactors::TRankModelHolder* RankModel;
    const NRTYFactors::TRankModelHolder* FastRankModel;
    const NRTYFactors::TRankModelHolder* FilterModel;
    const NRTYFactors::TRankModelHolder* FastFilterModel;

    const NGroupingAttrs::TDocsAttrs* DocsAttrs;
    THolder<NRTYFactors::TUserFactorsCalcer> UserFactorCalcer;
    TRequestParams* RP;
    TExtraFactors ExtraFactors;
    TExtraFactors ExtraFactorsFastRank;
    TString NamedFactorSet;
    TString QSReq;
    EFilterBorderMode FbMode;
    EFilterBorderMode FastFbMode;
    float FilterBorder;
    float FastFilterBorder;
    bool BorderKeepRefineDoc;
    bool AllFactors;
    bool AllFactorsExt;
    bool AllStaticFactors;
    bool SimulateNotJustFastRankForRTY; // for unit tests to check which factors are calculated during fastrank with IsJustFastRank
    bool UseExternalAnnCalcer;
    bool DisableQuorumAnn;
    NRTYFactors::TFactorPoliteness PoliteOpts;
    TVector<ui64> Kps;
    TMaybe<TString> TmName;
    TMaybe<bool> ImitateQrQuorum;
    bool EnableSoftnessInTextQuorum;
    bool RequestRtyFactors;
    ui32 FactorAnnHitsLimit = 0;

    THolder<TRTYSearchRequestContext> SearchContext;
    TRTYSearchStatistics SearchStatistics;

public:
    bool IsJustFastRank() const {
        return GetRP().IsJustFastRank() && !SimulateNotJustFastRankForRTY;
    }

    const TString& GetQSReq() const override {
        return QSReq;
    }

    const TExtraFactors* GetExtraFactors(bool fastRank) const override {
        if (fastRank && !IsJustFastRank()) {
            return &ExtraFactorsFastRank;
        }
        return &ExtraFactors;
    }

    const TString* GetNamedFactorSet(bool fastRank) const override {
        if (Y_LIKELY(!NamedFactorSet))
            return nullptr;
        if (fastRank && !IsJustFastRank())
            return nullptr;
        return &NamedFactorSet;
    }

    inline float GetFilterBorder() const override {
        return FilterBorder;
    }

    inline float GetFastFilterBorder() const override {
        return FastFilterBorder;
    }

    inline EFilterBorderMode GetFbMode() const override {
        return FbMode;
    }

    inline EFilterBorderMode GetFastFbMode() const override {
        return FastFbMode;
    }

    inline bool GetBorderKeepRefineDoc() const override {
        return BorderKeepRefineDoc;
    }

    TMaybe<TString> GetTmName() const override {
        return TmName;
    }

    inline const NRTYFactors::TRankModelHolder* GetFilterModel() const override {
        return FilterModel;
    }

    inline const NRTYFactors::TRankModelHolder* GetFastFilterModel() const override {
        return FastFilterModel;
    }

    inline const NRTYFactors::TRankModelHolder* GetRankModel() const override {
        return RankModel;
    }

    inline const NRTYFactors::TRankModelHolder* GetFastRankModel() const override {
        return FastRankModel;
    }

    inline TRequestParams& GetRP() const override {
        VERIFY_WITH_LOG(RP, "Invalid usage");
        return *RP;
    };

    ECalcFactors CalcAllFactors(bool fastRank) const override {
        if (fastRank) {
            if (AllFactorsExt) {
                return ECalcFactors::All;
            }
            if (AllFactors) {
                return ECalcFactors::LightAndFormula;
            }
        }
        if (AllFactors) {
            return ECalcFactors::All;
        }
        return ECalcFactors::Formula;
    };

    bool ShouldCalcAllStaticFactors() const override {
        return AllStaticFactors;
    }

    TVector<ui64> GetKps() const override {
        return Kps;
    }

    TComponentSearcher* GetPreSearcher() const override {
        return ComponentSearcher.Get();
    }

    IRTYDocProcessor* GetRtyDocProcessor() const override {
        return RtyDocProcessor.Get();
    }

    void FillDynamicContext(TRTYDynamicFeatureContext& ctx) const override;

    TMaybe<bool> ShouldImitateQrQuorum() const override {
        return ImitateQrQuorum;
    }

    bool IsSoftnessEnabledInTextQuorum() const override {
        return EnableSoftnessInTextQuorum;
    }

    bool AreRtyFactorsRequested() const override {
        return RequestRtyFactors;
    }

    bool ShouldUseExternalAnnCalcer() const override {
        // this also may be enabled for all requests in rty_ann config
        return UseExternalAnnCalcer;
    }

    bool IsQuorumAnnDisabled(bool rtyAnnSaas) const override;

    ui32 GetFactorAnnHitsLimit() const override {
        return FactorAnnHitsLimit;
    }

    TRTYCgiReader(const IArchiveData* ad, const IRemapperUrlDocId& remapper, const TRTYIndexData& indexData);

    void FillProperties(TSearcherProps* props) const;
    void TreatCgiParamRelevSet(TStringBuf value, TMap <ui32, ui32>& userSrcToDst);
    void TreatCgiParamRelev(
        const TString& value,
        TMap <ui32, ui32>& userSrcToDst,
        TVector<TString>& calcUserDirectives,
        TVector<TString>& storeUserDirectives,
        TString& formula,
        TString& fastFormula,
        TString& filterFormula,
        TString& fastFilterFormula,
        TString& extraFactorsSet,
        TString& baseRankModel,
        TString& polynom,
        TString& fastPolynom,
        TString& filterPolynom,
        TString& fastFilterPolynom,
        TVector<ui32>& extraFactorsIndicies,
        bool& invalidateCaches
    );
    void TreatCgiParamsIRelev(TRequestParams& rp, const TCgiParameters& cgiParams);
    void TreatCgiParamKps(const TCgiParameters& cgiParams);
    void TreatCgiParamFbMode(TStringBuf value, EFilterBorderMode& mode);
    void TreatCgiParams(TRequestParams& RP, const TCgiParameters& cgiParams) override;
    const NRTYFactors::TUserFactorsCalcer* GetUserFactorsCalcer() const override;
private:
    void AddExtraFactorsByNameFromCgi(const TCgiParameters& cgiParams, TStringBuf source);
};
