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

import com.google.common.reflect.TypeToken;
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.RegionFilterService;
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 com.tzld.piaoquan.recommend.server.util.JSONUtils;
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;

/**
 * @author zhangbo
 */
@Component
@Slf4j
public class CFRovnRecallStrategyV1 implements RecallStrategy {
    private final String CLASS_NAME = this.getClass().getSimpleName();
    @Autowired
    private RegionFilterService filterService;
    @Autowired
    @Qualifier("redisTemplate")
    public RedisTemplate<String, String> redisTemplate;
    @Override
    public List<Video> recall(RecallParam param) {
        long t0 = System.currentTimeMillis();
        List<Video> result = new ArrayList<>();
        // 1 获取头部vid，请求redis得到tag。
        Long headVid = param.getVideoId();
        String key1 = "redis:cf_rovn_vid:" + headVid;
        String value1 = redisTemplate.opsForValue().get(key1);
        if (value1 == null || value1.isEmpty()){
            return result;
        }
        Map<String, String> vfMap = new HashMap<>();
        vfMap = JSONUtils.fromJson(value1, new TypeToken<Map<String, String>>() {}, vfMap);
        List<Long> vids = new ArrayList<>();
        List<Double> scores = new ArrayList<>();
        try{
            vids = Arrays.stream(vfMap.getOrDefault("videoid_arr", "").split(","))
                    .filter(s -> !s.trim().isEmpty() && s.matches("-?\\d+"))
                    .map(Long::valueOf).collect(Collectors.toList());
            scores = Arrays.stream(vfMap.getOrDefault("score_arr", "").split(","))
                    .map(Double::valueOf).collect(Collectors.toList());
        }catch(Exception e){
            log.error(String.format("json parse is wrong in {}, key={}, error={}", CLASS_NAME, value1, e));
            vids = new ArrayList<>();
            scores = new ArrayList<>();
        }
        if (vids.size() != scores.size() || vids.isEmpty()){
            return result;
        }
        Map<Long, Double> vid2Score = new HashMap<>(vids.size());
        for (int i = 0; i < vids.size(); ++i){
            Long id = vids.get(i);
            if (id.equals(headVid)){
                continue;
            }
            Double score = scores.get(i);
            vid2Score.put(id, score);
        }

        FilterParam filterParam = FilterParamFactory.create(param, vids);
        FilterResult filterResult = filterService.filter(filterParam);
        List<Video> videosResult = new ArrayList<>();
        if (filterResult != null && CollectionUtils.isNotEmpty(filterResult.getVideoIds())) {
            filterResult.getVideoIds().forEach(vid -> {
                Video video = new Video();
                video.setVideoId(vid);
                video.setAbCode(param.getAbCode());
                video.setRovScore(vid2Score.getOrDefault(vid, 0.0D));
                video.setPushFrom(pushFrom());
                videosResult.add(video);
            });
        }

        // 5 内部日志打印

        // 6 返回结果
        videosResult.sort(Comparator.comparingDouble(o -> -o.getRovScore()));
        return videosResult;
    }

    public static final String PUSH_FORM = "recall_strategy_cf_rovn";

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

}
