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

import com.tzld.piaoquan.recommend.server.model.Video;
import com.tzld.piaoquan.recommend.server.service.rank.RankParam;
import com.tzld.piaoquan.recommend.server.util.DateUtils;
import com.tzld.piaoquan.recommend.server.util.FestiveUtil;
import com.tzld.piaoquan.recommend.server.util.ProbabilityCalculator;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;

/**
 * 提权处理器
 *
 * @author sunxy
 */
@Slf4j
public class RankProcessorBoost {

    public static void boostByTag(List<Video> rovList, Map<String, Map<String, String>> rulesMap) {
        if (CollectionUtils.isEmpty(rovList) || rulesMap == null || rulesMap.isEmpty()) {
            return;
        }
        Map<String, Double> boostMap = new HashMap<>(rulesMap.size());
        for (Map.Entry<String, Map<String, String>> entry : rulesMap.entrySet()) {
            String key = entry.getKey();
            Map<String, String> rule = entry.getValue();
            String boostRate = rule.get("boost");
            String boostDate = rule.get("boost_date");

            // 使用 calculateCurrentProbability 方法计算当前概率
            double currentProbability = ProbabilityCalculator.calculateCurrentProbability(boostRate, boostDate);
            boostMap.put(key, currentProbability);
        }

        for (Map.Entry<String, Double> entry : boostMap.entrySet()) {
            if (entry.getValue() <= 0) {
                continue;
            }
            try {
                Double value = entry.getValue();
                // 给每个tag的视频提权（乘 value）
                rovList.stream().filter(video -> video.getTags().contains(entry.getKey()))
                        .forEach(video -> video.setSortScore(
                                BigDecimal.valueOf(video.getSortScore())
                                        .multiply(BigDecimal.valueOf(value))
                                        .doubleValue()));
            } catch (Exception ignored) {
            }
        }
        rovList.sort((o1, o2) -> Double.compare(o2.getSortScore(), o1.getSortScore()));

    }

    public static void boostByMergeCate(List<Video> rovList, Map<String, List<Map<String, String>>> rulesMap) {

        if (CollectionUtils.isEmpty(rovList) || MapUtils.isEmpty(rulesMap)) {
            return;
        }

        for (Video video : rovList) {
            if (CollectionUtils.isEmpty(video.getMergeCateList())) {
                continue;
            }

            // 目前只有一个品类
            for (String mergeCate : video.getMergeCateList()) {
                double reduceCoefficient = RankProcessorBoost.parseReduceCoefficient(mergeCate, rulesMap);
                double originScore = video.getScore();
                video.setScore(originScore * reduceCoefficient);
                video.setSortScore(originScore * reduceCoefficient);
                video.getScoresMap().put("reduceCoefficient", reduceCoefficient);
            }

        }

        rovList.sort((o1, o2) -> Double.compare(o2.getSortScore(), o1.getSortScore()));

    }

    public static void boostByFestive(RankParam param, List<Video> rovList, Map<String, String> rankReduceByFestiveConfig) {

        String abCode = rankReduceByFestiveConfig.getOrDefault("abCode", "747");

        if (CollectionUtils.isEmpty(param.getAbExpCodes()) || StringUtils.isEmpty(abCode) || !param.getAbExpCodes().contains(abCode)) {
            return;
        }

        Set<String> festiveRootSessionIdTails = new HashSet<>(Arrays.asList(rankReduceByFestiveConfig.getOrDefault("festiveRootSessionIdTails", "0,1,2,3,4,a,b,c").split(",")));
        String rootSessionId = param.getRootSessionId();
        if (StringUtils.isBlank(rootSessionId) || CollectionUtils.isEmpty(festiveRootSessionIdTails)) {
            return;
        }
        String tail = rootSessionId.substring(rootSessionId.length() - 1);
        if (!festiveRootSessionIdTails.contains(tail)) {
            return;
        }


        double reduceCoefficient = Double.parseDouble(rankReduceByFestiveConfig.getOrDefault("reduceCoefficient", "0.2"));
        String format = "yyyy-MM-dd";
        int nowHour = LocalDateTime.now().getHour();
        LocalDate now = LocalDate.now();
        for (Video video : rovList) {
            String festiveName = video.getOtherParam().getOrDefault("fes_name", video.getOtherParam().getOrDefault("festive_label2", ""));
            if (StringUtils.isBlank(festiveName)) {
                continue;
            }
            List<String> festiveDateStrList = FestiveUtil.getDateByFestiveName(festiveName);
            if (CollectionUtils.isEmpty(festiveDateStrList)) {
                continue;
            }


            for (String festiveDateStr : festiveDateStrList) {
                LocalDate festiveDate = DateUtils.convertStrToLocalDate(festiveDateStr, format);
                // 计算今天与节日相差的天数，如果节日时间在今天之后，返回负数
                long diffDay = ChronoUnit.DAYS.between(festiveDate, now);
                boolean flag = (diffDay == 0 && nowHour >= 10) || (diffDay >= 1 && diffDay <= 2);
                if (flag) {
                    // log.info("[FestiveVideoReduce] video: {}, festiveName: {}, festiveDate: {}, reduceCoefficient: {}", video.getVideoId(), festiveName, festiveDateStr, reduceCoefficient);
                    double originScore = video.getScore();
                    video.setScore(originScore * reduceCoefficient);
                    video.setSortScore(originScore * reduceCoefficient);
                    video.getScoresMap().put("festiveReduceCoefficient", reduceCoefficient);
                    break;
                }
            }
        }
        rovList.sort((o1, o2) -> Double.compare(o2.getSortScore(), o1.getSortScore()));
    }

    private static double parseReduceCoefficient(String mergeCate2, Map<String, List<Map<String, String>>> reduceConfigMap) {
        if (StringUtils.isBlank(mergeCate2) || MapUtils.isEmpty(reduceConfigMap)) {
            return 1d;
        }

        List<Map<String, String>> configMaps = reduceConfigMap.getOrDefault(mergeCate2, new ArrayList<>());
        for (Map<String, String> configMap : configMaps) {
            boolean currentHourIsNeedReduce = RankProcessorBoost.currentHourIsNeedReduce(configMap);
            boolean currentDateIsNeedReduce = RankProcessorBoost.currentDateIsNeedReduce(configMap);
            if (currentHourIsNeedReduce || currentDateIsNeedReduce) {
                return Double.parseDouble(configMap.getOrDefault("reduce_coefficient", "1"));
            }
        }

        return 1d;
    }

    /**
     * 当前小时是否需要降权
     */
    private static boolean currentHourIsNeedReduce(Map<String, String> configMap) {
        if (!configMap.containsKey("reduce_hour")) {
            return false;
        }
        try {

            int currentHour = LocalDateTime.now().getHour();
            String[] reduceHours = configMap.get("reduce_hour").split(",");
            for (String hourRange : reduceHours) {
                String[] split = hourRange.split("-");
                int h1 = Integer.parseInt(split[0]);
                int h2 = (split.length == 2) ? Integer.parseInt(split[1]) : h1;

                if (currentHour >= h1 && currentHour <= h2) {
                    return true;
                }
            }
        } catch (Exception e) {
            log.error("564 error parse reduce hour config error. config content: {}, \n", configMap, e);
        }
        return false;
    }

    /**
     * 当前时间段是否需要降权
     */
    private static boolean currentDateIsNeedReduce(Map<String, String> configMap) {
        if (!configMap.containsKey("reduce_date")) {
            return false;
        }

        String[] reduceDates = configMap.get("reduce_date").split(",");
        for (String s : reduceDates) {
            if (DateUtils.ifTimeRangeInNow(s)) {
                return true;
            }
        }

        return false;
    }
}
