#include "prepare_ann.h"

#include <yweb/robot/userdata/indexann/lib/serializer_impl.h>
#include <library/cpp/string_utils/base64/base64.h>

#include <array>

namespace NIndexAnn {
    //
    // All IndexAnn features that match GetSaasProfile() filter
    // This list is kept and obtained via reflection initially (see "FeaturesListIsActual" unit test)
    //
    // To update, get the "expectedFeatures" value from the failed FeaturesListIsActual output, format
    // it appropriately and put it here
    //
    static const std::array<NIndexAnn::EDataType, 46> saasFeatures{
        DT_ALICE_MUSIC_STREAMS_TRACK_TITLE,
        DT_ALICE_MUSIC_STREAMS_ARTIST_NAME,
        DT_ALICE_MUSIC_STREAMS_ALBUM_TITLE,
        DT_ALICE_MUSIC_STREAMS_TRACK_ARTIST_NAMES,
        DT_ALICE_MUSIC_STREAMS_TRACK_ALBUM_TITLE,
        DT_ALICE_MUSIC_STREAMS_TRACK_LYRICS,
        DT_AVG_DT_WEIGHTED_BY_RANK_MOBILE,
        DT_BQPR,
        DT_BQPR_SAMPLE,
        DT_CORRECTED_CTR,
        DT_CORRECTED_CTR_LONG_PERIOD,
        DT_CORRECTED_CTR_XFACTOR,
        DT_DOUBLE_FRC,
        DT_EXP,
        DT_FIRST_CLICK_DT_XF,
        DT_FIRST_LAST_CLICK_MOBILE,
        DT_LONG_CLICK,
        DT_LONG_CLICK_MOBILE,
        DT_LONG_CLICK_SP,
        DT_META_TAG_SENTENCE,
        DT_NHOP,
        DT_ONE_CLICK,
        DT_ONE_CLICK_FRC_XF_SP,
        DT_POPULAR_SE_FRC_BROWSER,
        DT_QUERY_DWELL_TIME,
        DT_SAMPLE_PERIOD,
        DT_SIMPLE_CLICK,
        DT_SPLIT_DT,
        DT_VIDEO_PCTR_NEW,
        DT_VPCG_CORRECTED_CLICKS_SLP,
        DT_YABAR_TIME,
        DT_YABAR_VISITS,
        DT_MUSIC_STREAMS_FIRST_CLICK,
        DT_MUSIC_STREAMS_LAST_CLICK,
        DT_MUSIC_STREAMS_LONG_CLICK,
        DT_MUSIC_STREAMS_SINGLE_CLICK,
        DT_RC_SEARCH_CLICKS_D30T5,
        DT_KP_GENRE,
        DT_KP_CAST,
        DT_KP_CHARACTER,
        DT_KP_KEYWORD,
        DT_KP_AWARD,
        DT_KP_TAG,
        DT_KP_I2I_SIMILARITY,
        DT_KP_HANDMADE_SIMILARITY,
        DT_KP_PERSON_CHARACTER,
    };

    const NIndexAnn::IFeaturesProfile& GetSaasProfile() {
        // TComboProfile owns the objects, despite the semantics of a const pointer
        static NIndexAnn::TComboProfile instance({new TSaaSQuorumProfile, new TSaaSFactorProfile});
        return instance;
    }

    const TArrayRef<const NIndexAnn::EDataType> GetSaasFeatures() {
        return TArrayRef<const NIndexAnn::EDataType>(saasFeatures.data(), saasFeatures.size());
    };

    bool UnpackToSaasData(NRTYServer::TMessage::TSentenceData& saasAnn, const NIndexAnn::TAnnotationRec& ann, const NIndexAnn::IFeaturesProfile& featuresFilter) {
        const auto& annNamesProvider = NIndexAnn::TDataTypeConcern::Instance();

        Y_ASSERT(!saasAnn.HasText() && !saasAnn.StreamsByRegionSize() /*empty value expected*/);
        for (size_t i = 0; i < ann.DataSize(); ++i) {
            const NIndexAnn::TRegionData& record = ann.GetData(i);

            NIndexAnn::TSerializationContext ctx(record);
            NRTYServer::TMessage::TRegionData saasRegion;
            NIndexAnn::WriteAnnDataCb(ctx, [&](NIndexAnn::TSerializationContext& ctx) {
                if (featuresFilter.IsEssential(ctx.StreamId)) {
                    NRTYServer::TMessage::TStreamData& saasStream = *saasRegion.AddStreams();

                    saasStream.SetName(annNamesProvider.GetName(static_cast<NIndexAnn::EDataType>(ctx.StreamId)));
                    saasStream.MutableValue()->SetValue(Base64Encode({ctx.Buf.Data(), ctx.Buf.Size()}));
                    // streamValue.SetAction(NRTYServer::TMessage::TStreamData::SET); // This field is not used in SaaS
                }
            });

            if (Y_LIKELY(saasRegion.StreamsSize() != 0)) {
                saasRegion.SetRegion(ctx.Reg);
                *saasAnn.AddStreamsByRegion() = std::move(saasRegion);
            }
        }

        if (Y_LIKELY(saasAnn.StreamsByRegionSize() != 0)) {
            saasAnn.SetText(ann.GetText());
            saasAnn.SetTextLanguage(ann.GetTextLanguage());
            return true;
        } else {
            return false;
        }
    }

    bool UnpackToSaasData(NRTYServer::TMessage::TAnnData& saasData, const NIndexAnn::TIndexAnnSiteData& annData, const NIndexAnn::IFeaturesProfile& featuresFilter) {
        saasData.Clear();
        for (const NIndexAnn::TAnnotationRec& annRec : annData.get_arr_recs()) {
            NRTYServer::TMessage::TSentenceData saasAnnRec;
            bool ok = NIndexAnn::UnpackToSaasData(saasAnnRec, annRec, featuresFilter);
            if (ok) {
                *saasData.AddSentences() = std::move(saasAnnRec);
            }
        }
        return saasData.SentencesSize() != 0;
    }

}
