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

import com.tzld.piaoquan.recommend.server.model.Video;
import com.tzld.piaoquan.recommend.server.service.filter.FilterParam;
import com.tzld.piaoquan.recommend.server.service.filter.FilterResult;
import com.tzld.piaoquan.recommend.server.service.filter.FilterService;
import com.tzld.piaoquan.recommend.server.service.recall.FilterParamFactory;
import com.tzld.piaoquan.recommend.server.service.recall.RecallParam;
import com.tzld.piaoquan.recommend.server.service.recall.RecallStrategy;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

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

@Component
@Slf4j
public class SceneCFRovnRecallStrategy implements RecallStrategy {
    private final String CLASS_NAME = this.getClass().getSimpleName();
    @Autowired
    private FilterService filterService;
    @Autowired
    @Qualifier("redisTemplate")
    public RedisTemplate<String, String> redisTemplate;

    public static final String PUSH_FORM = "recall_strategy_scene_cf_rovn";
    public static final String redisKeyPrefix = "redis:scene_cf_recall:rovn";
    public static final Set<Long> hotSceneSet = new HashSet<>(Arrays.asList(1008L, 1007L, 1058L, 1074L, 1010L));

    @Override
    public String pushFrom() {
        return PUSH_FORM;
    }

    @Override
    public List<Video> recall(RecallParam param) {
        Long headVid = param.getVideoId();
        String redisKey = getRedisKey(param);
        List<Video> videosResult = new ArrayList<>();
        try {
            // 1 获取头部vid，请求redis得到vid & score。
            String redisValue = redisTemplate.opsForValue().get(redisKey);
            if (null == redisValue || redisValue.isEmpty()) {
                return videosResult;
            }
            Map<Long, Double> vid2Score = getIdScoreMap(headVid, redisValue);
            List<Long> vids = new ArrayList<>(vid2Score.keySet());
            FilterParam filterParam = FilterParamFactory.create(param, vids);
            FilterResult filterResult = filterService.filter(filterParam);
            if (filterResult != null && CollectionUtils.isNotEmpty(filterResult.getVideoIds())) {
                filterResult.getVideoIds().forEach(vid -> {
                    Video video = new Video();
                    video.setVideoId(vid);
                    video.setRovScore(vid2Score.getOrDefault(vid, 0.0D));
                    video.setPushFrom(pushFrom());
                    videosResult.add(video);
                });
            }

            // 5 内部日志打印

            // 6 返回结果
            videosResult.sort(Comparator.comparingDouble(o -> -o.getRovScore()));
        } catch (Exception e) {
            log.error("json parse is wrong in {}, key={}, error={}", CLASS_NAME, redisKey, e);
        }
        return videosResult;
    }

    private Map<Long, Double> getIdScoreMap(Long headVid, String data) {
        Map<Long, Double> idScoreMap = new HashMap<>();
        if (null != data) {
            String[] pair = data.split("\t");
            if (2 == pair.length) {
                List<Long> ids = Arrays.stream(pair[0].split(","))
                        .map(Long::valueOf).collect(Collectors.toList());
                List<Double> scores = Arrays.stream(pair[1].split(","))
                        .map(Double::valueOf).collect(Collectors.toList());
                if (!ids.isEmpty() && ids.size() == scores.size()) {
                    for (int i = 0; i < ids.size(); ++i) {
                        Long id = ids.get(i);
                        if (id.equals(headVid)) {
                            continue;
                        }
                        Double score = scores.get(i);
                        idScoreMap.put(id, score);
                    }
                }
            }
        }
        return idScoreMap;
    }


    private String getRedisKey(RecallParam param) {
        Long scene = param.getHotSceneType();
        Long headVid = param.getVideoId();
        String sceneTypeStr = "other";
        if (null != scene && hotSceneSet.contains(scene)) {
            sceneTypeStr = String.valueOf(scene);
        }
        return String.format("%s:%s:%d", redisKeyPrefix, sceneTypeStr, headVid);
    }
}
