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.FilterResult;
import com.tzld.piaoquan.recommend.server.service.filter.FlowPoolWithScoreFilterService;
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 org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;

import java.util.*;

/**
 * @author dyp
 */
public abstract class AbstractFlowPoolWithScoreRecallStrategy implements RecallStrategy {
    @Autowired
    @Qualifier("redisTemplate")
    protected RedisTemplate<String, String> redisTemplate;

    @Autowired
    protected FlowPoolWithScoreFilterService filterService;

    @Override
    public List<Video> recall(RecallParam param) {
        String flowPoolKey = flowPoolKey(param);

        int getSize = param.getSize() * 5;
        List<Video> results = new ArrayList<>();
        Set<ZSetOperations.TypedTuple<String>> data = redisTemplate.opsForZSet().reverseRangeWithScores(flowPoolKey, 0,
                getSize - 1);
        if (CollectionUtils.isEmpty(data)) {
            return null;
        }

        Map<Long, Double> videoScoreMap = new HashMap<>();
        Map<Long, String> videoFlowPoolMap = new LinkedHashMap<>();
        for (ZSetOperations.TypedTuple<String> t : data) {
            String[] values = t.getValue().split("-");
            videoFlowPoolMap.put(NumberUtils.toLong(values[0], 0), values[1]);
            videoScoreMap.put(NumberUtils.toLong(values[0], 0), t.getScore());
        }
        FilterResult filterResult = filterService.filter(FilterParamFactory.create(param, videoFlowPoolMap));

        if (filterResult != null && CollectionUtils.isNotEmpty(filterResult.getVideoIds())) {
            filterResult.getVideoIds().stream().forEach(vid -> {
                Video recallData = new Video();
                recallData.setVideoId(vid);
                recallData.setAbCode(param.getAbCode());
                recallData.setRovScore(videoScoreMap.get(vid));
                recallData.setPushFrom(pushFrom());
                recallData.setFlowPool(videoFlowPoolMap.get(vid));
                recallData.setFlowPoolAbtestGroup(param.getFlowPoolAbtestGroup());
                results.add(recallData);
            });
        }

        return results.subList(0, results.size() < param.getSize() ? results.size() : param.getSize());
    }

    abstract String flowPoolKey(RecallParam param);

}
