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.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.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.*;

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

    @Autowired
    protected FilterService filterService;

    @Override
    public List<Video> recall(RecallParam param) {
        Pair<String, String> flowPoolKeyAndLevel = flowPoolKeyAndLevel(param);
        String flowPoolKey = flowPoolKeyAndLevel.getLeft();
        String level = flowPoolKeyAndLevel.getRight();
        int getSize = param.getSize() * 5;
        List<Video> results = new ArrayList<>();
        List<String> data = redisTemplate.opsForSet().randomMembers(flowPoolKey, getSize);
        if (CollectionUtils.isEmpty(data)) {
            return Collections.emptyList();
        }
        Map<Long, String> videoFlowPoolMap = new LinkedHashMap<>();
        for (String value : data) {
            String[] values = value.split("-");
            videoFlowPoolMap.put(NumberUtils.toLong(values[0], 0), values[1]);
        }
        FilterResult filterResult = filterService.filter(FilterParamFactory.create(param,
                new ArrayList<>(videoFlowPoolMap.keySet())));
        if (filterResult != null && CollectionUtils.isNotEmpty(filterResult.getVideoIds())) {
            filterResult.getVideoIds().stream().forEach(vid -> {
                Video recallData = new Video();
                recallData.setVideoId(vid);
                recallData.setRovScore(RandomUtils.nextDouble(0, 100));
                recallData.setPushFrom(pushFrom());
                recallData.setFlowPool(videoFlowPoolMap.get(vid));
                recallData.setLevel(level);
                results.add(recallData);
            });
        }

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

    abstract Pair<String, String> flowPoolKeyAndLevel(RecallParam param);

}
