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

import com.tzld.piaoquan.recommend.server.model.Video;
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.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.lang3.StringUtils;
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 org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * @author dyp
 */
@Service
@Slf4j
public class SpecialRecallStrategy implements RecallStrategy {
    @Autowired
    @Qualifier("redisTemplate")
    private RedisTemplate<String, String> redisTemplate;

    public static final String LAST_VIDEO_KEY_FORMAT = "recall:last:special:%s:%s:%s";
    public static final String PUSH_FROM = "special_mid_videos";

    @Override
    public List<Video> recall(RecallParam param) {
        String keyNamePrefix = "special:videos:item:";
        String dateStr = DateUtils.getCurrentDateStr("yyyyMMdd");
        String specialKeyName = keyNamePrefix + dateStr;
        if (!redisTemplate.hasKey(specialKeyName)) {
            dateStr = DateUtils.getBeforeDaysDateStr("yyyyMMdd", 1);
            specialKeyName = keyNamePrefix + dateStr;
        }

        String lastSpecialRecallKey = String.format(LAST_VIDEO_KEY_FORMAT, param.getAppType(), param.getMid(), dateStr);
        String value = redisTemplate.opsForValue().get(lastSpecialRecallKey);
        Long idx = 0L;
        if (StringUtils.isNotBlank(value)) {
            idx = redisTemplate.opsForZSet().reverseRank(specialKeyName, value);
            if (idx == null) {
                idx = 0L;
            } else {
                idx += 1;
            }
        }

        int getSize = param.getSize() * 5;
        int freq = 0;
        List<Video> results = new ArrayList<>();
        while (results.size() < param.getSize()) {
            freq += 1;
            if (freq > 2) {
                break;
            }
            Set<ZSetOperations.TypedTuple<String>> data = redisTemplate.opsForZSet().reverseRangeWithScores(specialKeyName, idx, idx + getSize - 1);
            if (CollectionUtils.isEmpty(data)) {
                break;
            }
            idx += getSize;
            data.stream().forEach(t -> {
                Video video = new Video();
                video.setVideoId(NumberUtils.toLong(t.getValue(), 0L));
                video.setRovScore(t.getScore());
                video.setPushFrom(PUSH_FROM);
                video.setLastVideoKey(lastSpecialRecallKey);
                results.add(video);
            });
        }
        return results;
    }

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