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

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.recall.strategy.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author sunxy
 */
@Service
@Slf4j
public class FestivalStrategy4RankModel extends RankService {

    @Resource
    private RankStrategy4Density rankStrategy4Density;

    @Override
    public List<Video> mergeAndRankRovRecall(RankParam param) {
        List<Video> rovRecallRank = new ArrayList<>();
        rovRecallRank.addAll(extractAndSort(param, RegionHRecallStrategy.PUSH_FORM));
        rovRecallRank.addAll(extractAndSort(param, RegionHDupRecallStrategy.PUSH_FORM));
        rovRecallRank.addAll(extractAndSort(param, Region24HRecallStrategy.PUSH_FORM));
        rovRecallRank.addAll(extractAndSort(param, RegionRelative24HRecallStrategy.PUSH_FORM));
        rovRecallRank.addAll(extractAndSort(param, RegionRelative24HDupRecallStrategy.PUSH_FORM));
        removeDuplicate(rovRecallRank);
        String abCode = param.getAbCode();
        int sizeReturn = param.getSize();
        if (abCode != null && this.regionRecallReturnSize != null &&
                this.regionRecallReturnSize.containsKey(abCode) &&
                this.regionRecallReturnSize.get(abCode) != null) {
            sizeReturn = this.regionRecallReturnSize.get(abCode).getOrDefault("result_size", sizeReturn);
        }
        rovRecallRank = rovRecallRank.size() <= sizeReturn
                ? rovRecallRank
                : rovRecallRank.subList(0, sizeReturn);

        List<Video> festivalRecallVideoList = extractAndSort(param, FestivalRecallStrategyV1.PUSH_FORM);
        // 截断
        if (CollectionUtils.isNotEmpty(festivalRecallVideoList)) {
            rovRecallRank.addAll(festivalRecallVideoList.stream().limit(30).collect(Collectors.toList()));
        }
        // merge sim recall 和 return recall
        rovRecallRank.addAll(extractAndSort(param, SimHotVideoRecallStrategy.PUSH_FORM));
        rovRecallRank.addAll(extractAndSort(param, ReturnVideoRecallStrategy.PUSH_FORM));
        // 地域召回要做截取，再做融合排序
        removeDuplicate(rovRecallRank);

        // 融合排序
        List<String> videoIdKeys = rovRecallRank.stream()
                .map(t -> param.getRankKeyPrefix() + t.getVideoId())
                .collect(Collectors.toList());
        List<String> videoScores = redisTemplate.opsForValue().multiGet(videoIdKeys);
        if (CollectionUtils.isNotEmpty(videoScores)
                && videoScores.size() == rovRecallRank.size()) {
            for (int i = 0; i < videoScores.size(); i++) {
                rovRecallRank.get(i).setSortScore(NumberUtils.toDouble(videoScores.get(i), 0.0));
            }
            Collections.sort(rovRecallRank,
                    Comparator.comparingDouble(o -> -(o.getSortScore() * 0.1 * (o.getRovScore() / 100))));
        }

        return rovRecallRank;
    }

    @Override
    public RankResult mergeAndSort(RankParam param, List<Video> rovRecallRank,
                                   List<Video> flowPoolRank) {
        return rankStrategy4Density.mergeAndSort(param, rovRecallRank, flowPoolRank);
    }
}
