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

import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValue;
import com.google.common.reflect.TypeToken;
import com.tzld.piaoquan.recommend.server.common.base.RankItem;
import com.tzld.piaoquan.recommend.server.model.Video;
import com.tzld.piaoquan.recommend.server.service.rank.RankParam;
import com.tzld.piaoquan.recommend.server.service.rank.RankResult;
import com.tzld.piaoquan.recommend.server.service.rank.RankService;
import com.tzld.piaoquan.recommend.server.service.rank.extractor.ExtractorUtils;
import com.tzld.piaoquan.recommend.server.service.rank.extractor.RankExtractorItemTags;
import com.tzld.piaoquan.recommend.server.service.rank.processor.RankProcessorBoost;
import com.tzld.piaoquan.recommend.server.service.rank.processor.RankProcessorDensity;
import com.tzld.piaoquan.recommend.server.service.rank.processor.RankProcessorInsert;
import com.tzld.piaoquan.recommend.server.service.rank.processor.RankProcessorTagFilter;
import com.tzld.piaoquan.recommend.server.service.recall.strategy.*;
import com.tzld.piaoquan.recommend.server.util.CommonCollectionUtils;
import com.tzld.piaoquan.recommend.server.util.JSONUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.RandomUtils;
import org.springframework.stereotype.Service;

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

/**
 * @author zhangbo
 * @desc 地域召回融合 流量池汤姆森
 */
@Service
@Slf4j
public class RankStrategy4RegionMergeModelV654 extends RankStrategy4RegionMergeModelBasic {
    @ApolloJsonValue("${rank.score.merge.weightv654:}")
    private Map<String, Double> mergeWeight;
    final private String CLASS_NAME = this.getClass().getSimpleName();


    @Override
    public List<Video> mergeAndRankRovRecall(RankParam param) {
        Map<String, Double> mergeWeight = this.mergeWeight != null ? this.mergeWeight : new HashMap<>(0);
        //-------------------融-------------------
        //-------------------合-------------------
        //-------------------逻-------------------
        //-------------------辑-------------------
        List<Video> rovRecallRank = new ArrayList<>();
        Set<Long> setVideo = new HashSet<>();
        //-------------------老地域召回-------------------
        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);
        this.duplicate(setVideo, v0);
        rovRecallRank.addAll(v0);
        setVideo.addAll(v0.stream().map(Video::getVideoId).collect(Collectors.toSet()));
        //-------------------sim相似召回------------------
        List<Video> v5 = extractAndSort(param, SimHotVideoRecallStrategy.PUSH_FORM);
        v5 = v5.stream().filter(r-> !setVideo.contains(r.getVideoId())).collect(Collectors.toList());
        v5 = v5.subList(0, Math.min(mergeWeight.getOrDefault("v5", 5.0).intValue(), v5.size()));
        rovRecallRank.addAll(v5);
        setVideo.addAll(v5.stream().map(Video::getVideoId).collect(Collectors.toSet()));
        //-------------------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()));
        //-------------------节日特殊召回-------------------
        List<Video> v7 = extractAndSort(param, FestivalRecallStrategyV1.PUSH_FORM);
        v7 = v7.stream().filter(r-> !setVideo.contains(r.getVideoId())).collect(Collectors.toList());
        v7 = v7.subList(0, Math.min(mergeWeight.getOrDefault("v7", 5.0).intValue(), v7.size()));
        rovRecallRank.addAll(v7);
        setVideo.addAll(v7.stream().map(Video::getVideoId).collect(Collectors.toSet()));
        //-------------------基于cf rov n 召回-------------------
        List<Video> v8 = extractAndSort(param, CFRovnRecallStrategyV1.PUSH_FORM);
        v8 = v8.stream().filter(r-> !setVideo.contains(r.getVideoId())).collect(Collectors.toList());
        v8 = v8.subList(0, Math.min(mergeWeight.getOrDefault("v8", 6.0).intValue(), v8.size()));
        rovRecallRank.addAll(v8);
        setVideo.addAll(v8.stream().map(Video::getVideoId).collect(Collectors.toSet()));


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

        // 1 模型分
        List<String> rtFeaPart = new ArrayList<>();
        List<RankItem> items = model(rovRecallRank, param, rtFeaPart);
        List<String> rtFeaPartKey = new ArrayList<>(Arrays.asList("item_rt_fea_1day_partition", "item_rt_fea_1h_partition"));
        List<String> rtFeaPartKeyResult = this.redisTemplate.opsForValue().multiGet(rtFeaPartKey);
        Calendar calendar = Calendar.getInstance();
        String date = new SimpleDateFormat("yyyyMMdd").format(calendar.getTime());
        String hour = new SimpleDateFormat("HH").format(calendar.getTime());
        String rtFeaPart1h = date + hour;
        if (rtFeaPartKeyResult != null) {
            if (rtFeaPartKeyResult.get(1) != null) {
                rtFeaPart1h = rtFeaPartKeyResult.get(1);
            }
        }
        // 2 统计分
        String cur = rtFeaPart1h;
        List<String> datehours = new LinkedList<>(); // 时间是倒叙的
        for (int i = 0; i < 24; ++i) {
            datehours.add(cur);
            cur = ExtractorUtils.subtractHours(cur, 1);
        }
        for (RankItem item : items) {
            Map<String, Map<String, Double>> itemRealMap = item.getItemRealTimeFeature();
            List<Double> views = getStaticData(itemRealMap, datehours, "view_uv_list_1h");
            List<Double> shares = getStaticData(itemRealMap, datehours, "share_uv_list_1h");
            List<Double> allreturns = getStaticData(itemRealMap, datehours, "return_uv_list_1h");

            // 全部回流的rov和ros
            List<Double> share2allreturn = getRateData(allreturns, shares, 0.0, 0.0);
            Double share2allreturnScore = calScoreWeightNoTimeDecay(share2allreturn);
            item.scoresMap.put("share2allreturnScore", share2allreturnScore);
            List<Double> view2allreturn = getRateData(allreturns, views, 0.0, 0.0);
            Double view2allreturnScore = calScoreWeightNoTimeDecay(view2allreturn);
            item.scoresMap.put("view2allreturnScore", view2allreturnScore);

            // 全部回流
            Double allreturnsScore = calScoreWeightNoTimeDecay(allreturns);
            item.scoresMap.put("allreturnsScore", allreturnsScore);


        }
        // 3 融合公式
        List<Video> result = new ArrayList<>();
        double f = mergeWeight.getOrDefault("f", 0.1);
        double g = mergeWeight.getOrDefault("g", 1.0);
        for (RankItem item : items) {
            double share2allreturnScore = item.scoresMap.getOrDefault("share2allreturnScore", 0.0);
            double view2allreturnScore = item.scoresMap.getOrDefault("view2allreturnScore", 0.0);
            double score = 0.0;
            double allreturnsScore = item.scoresMap.getOrDefault("allreturnsScore", 0.0);
            if (allreturnsScore > 50) {
                score += (f * share2allreturnScore + g * view2allreturnScore);
            }else{
                score += (f * share2allreturnScore + g * view2allreturnScore) * 0.01;
            }
            Video video = item.getVideo();
            video.setScore(score);
            video.setSortScore(score);
            video.setScoreStr(item.getScoreStr());
            video.setScoresMap(item.getScoresMap());
            result.add(video);
        }
        result.sort(Comparator.comparingDouble(o -> -o.getSortScore()));
        return result;
    }


}
