package com.tzld.piaoquan.recommend.server.service.rank.strategy;

import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValue;
import com.tzld.piaoquan.recommend.server.common.base.RankItem;
import com.tzld.piaoquan.recommend.server.model.Video;
import com.tzld.piaoquan.recommend.server.service.FeatureService;
import com.tzld.piaoquan.recommend.server.service.rank.RankParam;
import com.tzld.piaoquan.recommend.server.service.rank.extractor.ExtractVideoMergeCate;
import com.tzld.piaoquan.recommend.server.service.recall.strategy.*;
import com.tzld.piaoquan.recommend.server.service.score.ScorerUtils;
import com.tzld.piaoquan.recommend.server.util.CommonCollectionUtils;
import com.tzld.piaoquan.recommend.server.util.ExtractFeature20250218;
import com.tzld.piaoquan.recommend.server.util.FeatureBucketUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class RankStrategy4RegionMergeModelV569 extends RankStrategy4RegionMergeModelBasic {
    @ApolloJsonValue("${rank.score.merge.weightv569:}")
    private Map<String, Double> mergeWeight;

    @Autowired
    private FeatureService featureService;

    @Override
    public List<Video> mergeAndRankRovRecall(RankParam param) {

        long startTime = System.currentTimeMillis();

        Map<String, Double> mergeWeight = this.mergeWeight != null ? this.mergeWeight : new HashMap<>(0);
        //-------------------融-------------------
        //-------------------合-------------------
        //-------------------逻-------------------
        //-------------------辑-------------------

        List<Video> oldRovs = new ArrayList<>();
        oldRovs.addAll(extractAndSort(param, RegionHRecallStrategy.PUSH_FORM));
        oldRovs.addAll(extractAndSort(param, RegionHDupRecallStrategy.PUSH_FORM));
        oldRovs.addAll(extractAndSort(param, Region24HRecallStrategy.PUSH_FORM));
        oldRovs.addAll(extractAndSort(param, RegionRelative24HRecallStrategy.PUSH_FORM));
        oldRovs.addAll(extractAndSort(param, RegionRelative24HDupRecallStrategy.PUSH_FORM));
        removeDuplicate(oldRovs);
        int sizeReturn = param.getSize();
        List<Video> v0 = oldRovs.size() <= sizeReturn
                ? oldRovs
                : oldRovs.subList(0, sizeReturn);
        Set<Long> setVideo = new HashSet<>();
        this.duplicate(setVideo, v0);
        setVideo.addAll(v0.stream().map(Video::getVideoId).collect(Collectors.toSet()));
        List<Video> rovRecallRank = new ArrayList<>(v0);
        //-------------------return相似召回------------------
        List<Video> v6 = extractAndSort(param, ReturnVideoRecallStrategy.PUSH_FORM);
        v6 = v6.stream().filter(r -> !setVideo.contains(r.getVideoId())).collect(Collectors.toList());
        v6 = v6.subList(0, Math.min(mergeWeight.getOrDefault("v6", 5.0).intValue(), v6.size()));
        rovRecallRank.addAll(v6);
        setVideo.addAll(v6.stream().map(Video::getVideoId).collect(Collectors.toSet()));
        //-------------------新地域召回------------------
        List<Video> v1 = extractAndSort(param, RegionRealtimeRecallStrategyV1.PUSH_FORM);
        v1 = v1.stream().filter(r -> !setVideo.contains(r.getVideoId())).collect(Collectors.toList());
        v1 = v1.subList(0, Math.min(mergeWeight.getOrDefault("v1", 5.0).intValue(), v1.size()));
        rovRecallRank.addAll(v1);
        setVideo.addAll(v1.stream().map(Video::getVideoId).collect(Collectors.toSet()));
        //-------------------scene cf rovn------------------
        List<Video> sceneCFRovn = extractAndSort(param, SceneCFRovnRecallStrategy.PUSH_FORM);
        sceneCFRovn = sceneCFRovn.stream().filter(r -> !setVideo.contains(r.getVideoId())).collect(Collectors.toList());
        sceneCFRovn = sceneCFRovn.subList(0, Math.min(mergeWeight.getOrDefault("sceneCFRovn", 5.0).intValue(), sceneCFRovn.size()));
        rovRecallRank.addAll(sceneCFRovn);
        setVideo.addAll(sceneCFRovn.stream().map(Video::getVideoId).collect(Collectors.toSet()));
        //-------------------scene cf rosn------------------
        List<Video> sceneCFRosn = extractAndSort(param, SceneCFRosnRecallStrategy.PUSH_FORM);
        sceneCFRosn = sceneCFRosn.stream().filter(r -> !setVideo.contains(r.getVideoId())).collect(Collectors.toList());
        sceneCFRosn = sceneCFRosn.subList(0, Math.min(mergeWeight.getOrDefault("sceneCFRosn", 5.0).intValue(), sceneCFRosn.size()));
        rovRecallRank.addAll(sceneCFRosn);
        setVideo.addAll(sceneCFRosn.stream().map(Video::getVideoId).collect(Collectors.toSet()));


        //-------------------排-------------------
        //-------------------序-------------------
        //-------------------逻-------------------
        //-------------------辑-------------------

        // 1 批量获取特征  省份参数要对齐  headvid  要传递过来！
        List<String> vids = CommonCollectionUtils.toListDistinct(rovRecallRank, v -> String.valueOf(v.getVideoId()));

        // k1:视频、k2:表、k3:特征、v:特征值
        String provinceCn = param.getProvince().replaceAll("省$", "");
        String headVid = String.valueOf(param.getHeadVid());
        String sceneType = String.valueOf(param.getHotSceneType());
        Map<String, Map<String, Map<String, String>>> videoBaseInfoMap = featureService.getVideoBaseInfo(headVid, vids);
        String appType = String.valueOf(param.getAppType());
        String brand = "";
        if (Objects.nonNull(param.getMachineInfo())) {
            brand = param.getMachineInfo().getBrand();
        }

        long ts = System.currentTimeMillis() / 1000;

        FeatureService.Feature feature = featureService.getFeatureByNewLabel(appType, sceneType, provinceCn, brand, param.getMid(), headVid, vids, videoBaseInfoMap);
        Map<String, Map<String, String>> featureOriginUser = feature.getUserFeature();
        Map<String, Map<String, Map<String, String>>> featureOriginVideo = feature.getVideoFeature();
        Map<String, String> headVideoInfo = videoBaseInfoMap.getOrDefault(headVid, new HashMap<>()).getOrDefault("alg_vid_feature_basic_info", new HashMap<>());

        // 2 特征处理
        Map<String, Double> userFeatureMapDouble = new HashMap<>();

        Map<String, String> c1 = featureOriginUser.getOrDefault("mid_global_feature_20250212", new HashMap<>());
        Map<String, String> c4 = featureOriginUser.getOrDefault("mid_u2u_friend_index_feature_20250212", new HashMap<>());
        Map<String, String> c5 = featureOriginUser.getOrDefault("alg_mid_feature_return_tags", new HashMap<>());
        Map<String, String> c6 = featureOriginUser.getOrDefault("alg_mid_feature_share_tags", new HashMap<>());
        Map<String, String> c7 = featureOriginUser.getOrDefault("alg_mid_feature_sharecf", new HashMap<>());
        Map<String, String> c8 = featureOriginUser.getOrDefault("alg_mid_feature_returncf", new HashMap<>());

        ExtractFeature20250218.handleC1(c1, userFeatureMapDouble);
        ExtractFeature20250218.handleC4(c4, userFeatureMapDouble);
        Map<String, Map<String, String[]>> c78FeatureMap = ExtractFeature20250218.handleC7ToC8(c7, c8);

        List<RankItem> rankItems = CommonCollectionUtils.toList(rovRecallRank, RankItem::new);
        for (RankItem item : rankItems) {

            String vidStr = String.valueOf(item.getVideoId());

            Map<String, Double> featureMap = new HashMap<>();
            Map<String, String> v1Feature = videoBaseInfoMap.getOrDefault(vidStr, new HashMap<>()).getOrDefault("alg_vid_feature_basic_info", new HashMap<>());
            Map<String, Map<String, String>> videoFeatureMap = featureOriginVideo.getOrDefault(vidStr, new HashMap<>());
            Map<String, String> b1 = videoFeatureMap.getOrDefault("alg_vid_global_feature_20250212", new HashMap<>());
            Map<String, String> b2 = videoFeatureMap.getOrDefault("alg_vid_recommend_exp_feature_20250212", new HashMap<>());
            Map<String, String> b3 = videoFeatureMap.getOrDefault("alg_vid_recommend_flowpool_exp_feature_20250212", new HashMap<>());
            Map<String, String> b4 = videoFeatureMap.getOrDefault("alg_vid_apptype_recommend_exp_feature_20250212", new HashMap<>());
            Map<String, String> b5 = videoFeatureMap.getOrDefault("alg_vid_province_recommend_exp_feature_20250212", new HashMap<>());
            Map<String, String> b6 = videoFeatureMap.getOrDefault("alg_vid_brand_recommend_exp_feature_20250212", new HashMap<>());
            Map<String, String> b7 = videoFeatureMap.getOrDefault("alg_vid_hotsencetype_recommend_exp_feature_20250212", new HashMap<>());
            Map<String, String> b8 = videoFeatureMap.getOrDefault("alg_merge_cate1_recommend_exp_feature_20250212", new HashMap<>());
            Map<String, String> b9 = videoFeatureMap.getOrDefault("alg_merge_cate2_recommend_exp_feature_20250212", new HashMap<>());
            Map<String, String> b10 = videoFeatureMap.getOrDefault("alg_channel_recommend_exp_feature_20250212", new HashMap<>());
            Map<String, String> b11 = videoFeatureMap.getOrDefault("alg_festive_recommend_exp_feature_20250212", new HashMap<>());
            Map<String, String> b12 = videoFeatureMap.getOrDefault("alg_vid_long_period_recommend_exp_feature_20250212", new HashMap<>());
            Map<String, String> b13 = videoFeatureMap.getOrDefault("alg_video_unionid_recommend_exp_feature_20250212", new HashMap<>());

            Map<String, String> c2 = videoFeatureMap.getOrDefault("mid_merge_cate1_feature_20250212", new HashMap<>());
            Map<String, String> c3 = videoFeatureMap.getOrDefault("mid_merge_cate2_feature_20250212", new HashMap<>());

            Map<String, String> d1 = videoFeatureMap.getOrDefault("scene_type_vid_cf_feature_20250212", new HashMap<>());
            Map<String, String> d2 = videoFeatureMap.getOrDefault("vid_click_cf_feature_20250212", new HashMap<>());
            Map<String, String> d3 = videoFeatureMap.getOrDefault("alg_recsys_feature_cf_i2i_v2", new HashMap<>());

            Map<String, Map<String, String>> b2ToB11AndB13Map = new HashMap<>();
            b2ToB11AndB13Map.put("b2", b2);
            b2ToB11AndB13Map.put("b3", b3);
            b2ToB11AndB13Map.put("b4", b4);
            b2ToB11AndB13Map.put("b5", b5);
            b2ToB11AndB13Map.put("b6", b6);
            b2ToB11AndB13Map.put("b7", b7);
            b2ToB11AndB13Map.put("b8", b8);
            b2ToB11AndB13Map.put("b9", b9);
            b2ToB11AndB13Map.put("b10", b10);
            b2ToB11AndB13Map.put("b11", b11);
            b2ToB11AndB13Map.put("b13", b13);

            ExtractFeature20250218.handleB1(b1, featureMap);
            ExtractFeature20250218.handleB12(b12, featureMap);
            ExtractFeature20250218.handleB2ToB11AndB13(b2ToB11AndB13Map, featureMap);
            ExtractFeature20250218.handleC2ToC3(c2, c3, featureMap);
            ExtractFeature20250218.useC7ToC8(c78FeatureMap, vidStr, featureMap);
            ExtractFeature20250218.handleC5ToC6(c5, c6, v1Feature, featureMap);
            ExtractFeature20250218.handleD1(d1, featureMap);
            ExtractFeature20250218.handleD2(d2, featureMap);
            ExtractFeature20250218.handleD3(d3, featureMap);
            ExtractFeature20250218.handleVideoBasicFeature(v1Feature, ts, featureMap);
            ExtractFeature20250218.handleVideoSimilarity(v1Feature, headVideoInfo, featureMap);

            item.featureMapDouble = featureMap;
        }

        // 3 连续值特征分桶
        Map<String, Float> userFeatureMap = FeatureBucketUtils.bucketFeatureV2("20250218_bucket_322.txt", userFeatureMapDouble);
        for (RankItem item : rankItems) {
            Map<String, Double> featureMapDouble = item.featureMapDouble;
            item.featureMap = FeatureBucketUtils.bucketFeatureV2("20250218_bucket_322.txt", featureMapDouble);
        }


        // 4.1 排序模型计算 - str
        Map<String, Float> sceneFeatureMap = new HashMap<>(0);
        List<RankItem> items = ScorerUtils.getScorerPipeline("feeds_score_config_xgb_str_20250228.conf").scoring(sceneFeatureMap, userFeatureMap, rankItems);

        // 4.2 排序模型计算 - ros
        this.addRosScore(rankItems, userFeatureMapDouble, sceneFeatureMap);

        // 5 排序公式特征
        double xgbRovNegRate = mergeWeight.getOrDefault("xgbRovNegRate", 0.05);
        double calcVorMode = mergeWeight.getOrDefault("calcVorMode", 1d);
        double calcRosMode = mergeWeight.getOrDefault("calcRosMode", 1d);
        double calcStrMode = mergeWeight.getOrDefault("calcStrMode", 0d);


        Map<String, Map<String, String>> vid2MapFeature = this.getVideoRedisFeature(vids, "redis:vid_hasreturn_vor_4share:");
        List<Video> result = new ArrayList<>();
        for (RankItem item : items) {
            double score;
            double fmRovOrigin = item.getScoreRov();
            item.getScoresMap().put("fmRovOrigin", fmRovOrigin);
            double fmRov = restoreScore(fmRovOrigin, xgbRovNegRate);
            fmRov = this.handleStr(fmRov, calcStrMode, item, mergeWeight);


            item.getScoresMap().put("fmRov", fmRov);
            item.getScoresMap().put("xgbRovNegRate", xgbRovNegRate);
            item.getScoresMap().put("calcStrMode", calcStrMode);


            Map<String, String> vidFeatureMap = vid2MapFeature.getOrDefault(String.valueOf(item.getVideoId()), new HashMap<>());

            double vor24h = Double.parseDouble(vidFeatureMap.getOrDefault("vor_24h", "0"));
            double vor = this.handleVor(vor24h, calcVorMode, item, mergeWeight);

            // double originScoreRos = item.getScoreRos();
            double originScoreRos = Double.parseDouble(vidFeatureMap.getOrDefault("ros_24h", "0d"));
            double scoreRos = this.handleRos(originScoreRos, calcRosMode, item, mergeWeight);

            double rosAdd = mergeWeight.getOrDefault("ros_add", 0.1);
            double vorAdd = mergeWeight.getOrDefault("vor_add", 0.1);

            item.getScoresMap().put("hasReturnRovScore", scoreRos);
            item.getScoresMap().put("originVor", vor24h);
            item.getScoresMap().put("vor", vor);
            item.getScoresMap().put("calcVorMode", calcVorMode);
            item.getScoresMap().put("calcRosMode", calcRosMode);
            item.getScoresMap().put("originRos", originScoreRos);
            item.getScoresMap().put("rosAdd", rosAdd);
            item.getScoresMap().put("vorAdd", vorAdd);
            score = fmRov * (rosAdd + scoreRos) * (vorAdd + vor);


            Video video = item.getVideo();
            video.setScore(score);
            video.setSortScore(score);
            video.setScoresMap(item.getScoresMap());

            Map<String, String> allFeatureMap = new HashMap<>();
            item.getFeatureMapDouble().forEach((key, value) -> allFeatureMap.put(key, String.valueOf(value)));
            video.setAllFeatureMap(allFeatureMap);

            String mergeCate2 = ExtractVideoMergeCate.parseMergeCate2(String.valueOf(item.getVideoId()), featureOriginVideo);
            if (StringUtils.isNotBlank(mergeCate2)) {
                video.getMergeCateList().add(mergeCate2);
            }

            if (MapUtils.isNotEmpty(feature.getVideoFeature()) && MapUtils.isNotEmpty(feature.getVideoFeature().get(item.getVideoId() + ""))) {
                video.getMetaFeatureMap().putAll(feature.getVideoFeature().get(item.getVideoId() + ""));
            }
            if (MapUtils.isNotEmpty(videoBaseInfoMap) && MapUtils.isNotEmpty(videoBaseInfoMap.get(item.getVideoId() + ""))) {
                video.getMetaFeatureMap().putAll(videoBaseInfoMap.get(item.getVideoId() + ""));
            }
            if (MapUtils.isNotEmpty(headVideoInfo)) {
                video.getMetaFeatureMap().put("head_video", headVideoInfo);
            }
            if (MapUtils.isNotEmpty(feature.getUserFeature())) {
                video.getMetaFeatureMap().putAll(feature.getUserFeature());
            }

            // 将空的特征表过滤
            video.getMetaFeatureMap().entrySet().removeIf(e -> MapUtils.isEmpty(e.getValue()));

            result.add(video);
        }
        ExtractVideoMergeCate.addOtherParam(result, videoBaseInfoMap);
        result.sort(Comparator.comparingDouble(o -> -o.getSortScore()));

        log.info("569 run time: {}", (System.currentTimeMillis() - startTime));

        return result;
    }

    /**
     * ros模型打分
     */
    private void addRosScore(List<RankItem> rankItems, Map<String, Double> userFeatureMapDouble, Map<String, Float> sceneFeatureMap) {
        List<RankItem> rosRankItems = new ArrayList<>(rankItems.size());
        for (RankItem rankItem : rankItems) {
            RankItem rosRankItem = new RankItem(rankItem.getVideo());
            rosRankItem.rosFeatureMap = FeatureBucketUtils.bucketFeatureV2("20250306_ros_bucket_229.txt", rankItem.featureMapDouble);
            rosRankItems.add(rosRankItem);
        }
        Map<String, Float> userFeatureMap = FeatureBucketUtils.bucketFeatureV2("20250306_ros_bucket_229.txt", userFeatureMapDouble);
        ScorerUtils.getScorerPipeline("feeds_score_config_xgb_ros_20250311.conf").scoring(sceneFeatureMap, userFeatureMap, rosRankItems);

        // 将ros分数补充到之前的列表中
        Map<Long, RankItem> vidRosMap = new HashMap<>(rosRankItems.size());
        for (RankItem rosRankItem : rosRankItems) {
            vidRosMap.put(rosRankItem.getVideoId(), rosRankItem);
        }

        for (RankItem rankItem : rankItems) {
            if (vidRosMap.containsKey(rankItem.getVideoId())) {
                RankItem rosRankItem = vidRosMap.get(rankItem.getVideoId());
                rankItem.setScoreRos(rosRankItem.getScoreRos());
                rankItem.getScoresMap().put("RosXGBScore", rosRankItem.getScoreRos());
            }
        }
    }
}
