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

import com.tzld.piaoquan.recommend.server.common.ThreadPoolFactory;
import com.tzld.piaoquan.recommend.server.repository.VideoAppTypeStatus;
import com.tzld.piaoquan.recommend.server.repository.VideoAppTypeStatusRepository;
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 AppletVideoStatusStrategy implements FilterStrategy {
    @Autowired
    @Qualifier("videoRedisTemplate")
    private RedisTemplate<String, String> videoRedisTemplate;

    @Autowired
    private VideoAppTypeStatusRepository videoAppTypeStatusRepository;


    private final String videoAppTypeStatusKeyFormat = "video:active:status:%s:%s";


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

    /**
     * 过滤上下架状态
     * <p>
     * 紧急需求上线
     * 性能待优化
     *
     * @param idList  videoId列表
     * @param appType appType
     */
    private List<Long> filterActiveStatusVideoId(List<Long> idList, Integer appType) {
        if (CollectionUtils.isEmpty(idList)) {
            return idList;
        }
        List<String> keys = idList.stream()
                .map(id -> String.format(videoAppTypeStatusKeyFormat, appType, id))
                .collect(Collectors.toList());
        List<String> activeStatusList = videoRedisTemplate.opsForValue().multiGet(keys);
        if (activeStatusList == null) {
            activeStatusList = new ArrayList<>();
        }

        List<Long> cacheMissVideoIds = new ArrayList<>();
        Map<String, String> updateRedisStatus = new HashMap<>();
        Map<Long, Integer> activeStatusMap = new HashMap<>();
        for (int i = 0; i < idList.size(); i++) {
            String value = activeStatusList.get(i);
            if (StringUtils.isBlank(value)) {
                cacheMissVideoIds.add(idList.get(i));
            } else {
                activeStatusMap.put(idList.get(i), NumberUtils.toInt(value));
            }
        }

        if (CollectionUtils.isNotEmpty(cacheMissVideoIds)) {
            List<VideoAppTypeStatus> videoAppTypeStatusList = videoAppTypeStatusRepository.findAllByVideoIdInAndAppType(cacheMissVideoIds, appType);
            Set<Long> cacheMissVideoIdSet = new HashSet<>(cacheMissVideoIds);
            if (CollectionUtils.isNotEmpty(videoAppTypeStatusList)) {
                // 数据库有数据
                for (VideoAppTypeStatus videoAppTypeStatus : videoAppTypeStatusList) {
                    activeStatusMap.put(videoAppTypeStatus.getVideoId(), videoAppTypeStatus.getVideoStatus());
                    updateRedisStatus.put(String.format(videoAppTypeStatusKeyFormat, appType,
                            videoAppTypeStatus.getVideoId()), videoAppTypeStatus.getVideoStatus().toString());
                    cacheMissVideoIdSet.remove(videoAppTypeStatus.getVideoId());
                }
            }
            // 数据库无数据的videoId
            if (CollectionUtils.isNotEmpty(cacheMissVideoIdSet)) {
                for (Long videoId : cacheMissVideoIdSet) {
                    // 设置默认值
                    updateRedisStatus.put(String.format(videoAppTypeStatusKeyFormat, appType, videoId), "1");
                    activeStatusMap.put(videoId, 1);
                }
            }
        }

        // 异步更新缓存
        ThreadPoolFactory.defaultPool().execute(() -> videoRedisTemplate.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();
                updateRedisStatus.forEach((key, value) -> operations.set(key, value, RandomUtils.nextInt(10, 15),
                        TimeUnit.DAYS));
                return null;
            }
        }));

        return idList.stream()
                .filter(id -> activeStatusMap.containsKey(id) && activeStatusMap.get(id) == 1)
                .collect(Collectors.toList());

    }

}
