package com.tzld.piaoquan.recommend.server.service.rank.processor;
import com.tzld.piaoquan.recommend.server.model.Video;

import java.util.*;

public class RankProcessorDensity {

    public static List<Video> mergeDensityControl(
            List<Video> data, List<Video> rov, List<Video> flow, Map<String, Integer> rule
    ) {
        // 1 判断是否满足规则
        Map<String, Integer> statusCur = new HashMap<>();
        for (Video v : data) {
            List<String> tags = v.getTags();
            for (String t : tags) {
                if (rule.containsKey(t)) {
                    statusCur.put(t, statusCur.getOrDefault(t, 0) + 1);
                }
            }

        }
        Map<String, Integer> statusCurIllegal = new HashMap<>();
        for (Map.Entry<String, Integer> entry : statusCur.entrySet()) {
            String k = entry.getKey();
            Integer v = entry.getValue();
            if (rule.containsKey(k) && rule.get(k) < v) {
                statusCurIllegal.put(k, v - rule.get(k));
            }
        }

        if (statusCurIllegal.isEmpty()) {
            return data;
        }

        // 2 反向遍历，直到statusCurIllegal满足，记录要替换的index和召回池标记。
        List<Integer> indexes = new ArrayList<>();
        List<String> pushes = new ArrayList<>();
        for (int i = data.size() - 1; i >= 0; i--) {
            Video video = data.get(i);
            List<String> tags = video.getTags();
            Set<String> inters = new HashSet<>(tags);
            // intersection of tags and statusCurIllegal keys
            inters.retainAll(statusCurIllegal.keySet());
            if (inters.isEmpty()) {
                continue;
            }
            indexes.add(i);
            if (video.getFlowPool() != null){
                pushes.add(video.getFlowPool());
            }else{
                pushes.add("");
            }

            for (String inter : inters) {
                statusCurIllegal.put(inter, statusCurIllegal.get(inter) - 1);
                if (statusCurIllegal.get(inter) == 0) {
                    statusCurIllegal.remove(inter);
                }
                statusCur.put(inter, statusCur.get(inter) - 1);
                if (statusCur.get(inter) == 0) {
                    statusCur.remove(inter);
                }
            }
        }

        // 3 反向遍历index，再正向遍历增补列表，取可替换的video
        Collections.reverse(indexes);
        Collections.reverse(pushes);
        for (int j = 0; j < indexes.size(); j++) {
            int index = indexes.get(j);
            String push = pushes.get(j);
            List<Video> candidate;
            if (!push.isEmpty()) {
                // 5 如果是flow的video0 取不到 不做替换
                candidate = flow;
            } else {
                // 5 如果是rov的video  取不到 不做替换
                candidate = rov;
            }
            for (int i = 0; i < candidate.size(); i++) {
                Video videoNew = candidate.get(i);
                Set<String> judgeRuleSet = judgeRule(rule, statusCur);
                Set<String> tags1 = new HashSet<>(videoNew.getTags());
                tags1.retainAll(judgeRuleSet);
                if (!tags1.isEmpty()) {
                    continue;
                }
                // 开始插入
                Video tmp = data.get(index);
                data.set(index, videoNew);
                candidate.set(i, tmp);
                // 更新状态
                Set<String> tags2 = new HashSet<>(videoNew.getTags());
                for (String tag : tags2) {
                    if (rule.containsKey(tag)){
                        statusCur.put(tag, statusCur.getOrDefault(tag, 0) + 1);
                    }
                }
                break;
            }
            if (!push.isEmpty()) {
                flow = candidate;
            } else {
                rov = candidate;
            }
        }
        return data;
    }

    public static Set<String> judgeRule(Map<String, Integer> rule, Map<String, Integer> status) {
        Set<String> result = new HashSet<>();
        for (Map.Entry<String, Integer> entry : status.entrySet()) {
            String k = entry.getKey();
            Integer v = entry.getValue();
            if (rule.containsKey(k) && rule.get(k) <= v) {
                result.add(k);
            }
        }
        return result;
    }
}
