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

import com.tzld.piaoquan.recommend.server.common.ThreadPoolFactory;
import com.tzld.piaoquan.recommend.server.repository.WxVideoStatus;
import com.tzld.piaoquan.recommend.server.repository.WxVideoStatusRepository;
import com.tzld.piaoquan.recommend.server.service.filter.FilterParam;
import com.tzld.piaoquan.recommend.server.service.filter.FilterStrategy;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

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

/**
 * @author dyp
 */
@Component
@Slf4j
public class RecommendStatusStrategy implements FilterStrategy {
    @Autowired
    @Qualifier("redisTemplate")
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private WxVideoStatusRepository wxVideoStatusRepository;

    private final String keyFormat = "video:recommend:status:%s";

    private static final int RECOMMEND_STATUS = -6;

    @Override
    public List<Long> filter(FilterParam param) {
        if (param == null
                || CollectionUtils.isEmpty(param.getVideoIds())) {
            return Collections.emptyList();
        }

        List<String> keys = param.getVideoIds().stream()
                .map(id -> String.format(keyFormat, id))
                .collect(Collectors.toList());

        List<String> recommendStatus = redisTemplate.opsForValue().multiGet(keys);
        List<Long> cacheMissVideoIds = new ArrayList<>();
        Map<Long, Integer> recommendStatusMap = new HashMap<>();
        for (int i = 0; i < param.getVideoIds().size(); i++) {
            String value = recommendStatus.get(i);
            if (StringUtils.isBlank(value)) {
                cacheMissVideoIds.add(param.getVideoIds().get(i));
            } else {
                recommendStatusMap.put(param.getVideoIds().get(i), NumberUtils.toInt(value));
            }
        }

        if (CollectionUtils.isNotEmpty(cacheMissVideoIds)) {
            List<WxVideoStatus> status = wxVideoStatusRepository.findAllByVideoIdIn(cacheMissVideoIds);
            if (CollectionUtils.isNotEmpty(status)) {
                for (WxVideoStatus v : status) {
                    recommendStatusMap.put(v.getVideoId(), v.getRecommendStatus());

                    // TODO 异步更新缓存
                    ThreadPoolFactory.defaultPool().execute(() -> {
                        redisTemplate.executePipelined(new SessionCallback<String>() {
                            @Override
                            public <A, B> String execute(RedisOperations<A, B> redisOperations) throws DataAccessException {
                                ValueOperations<String, String> operations =
                                        (ValueOperations<String, String>) redisOperations.opsForValue();
                                status.forEach(v -> {
                                    operations.set(String.format(keyFormat, v.getVideoId()),
                                            String.valueOf(v.getRecommendStatus()), RandomUtils.nextInt(30, 60),
                                            TimeUnit.SECONDS);
                                });

                                return null;
                            }
                        });
                    });
                }
            }
        }


        return param.getVideoIds().stream()
                .filter(id -> recommendStatusMap.containsKey(id) && recommendStatusMap.get(id) == RECOMMEND_STATUS)
                .collect(Collectors.toList());

    }

}
