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

import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValue;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.tzld.piaoquan.recommend.server.common.RedisKeyConstants;
import com.tzld.piaoquan.recommend.server.repository.WxUserInfo;
import com.tzld.piaoquan.recommend.server.repository.WxUserInfoRepository;
import com.tzld.piaoquan.recommend.server.repository.WxVideoTagRel;
import com.tzld.piaoquan.recommend.server.repository.WxVideoTagRelRepository;
import com.tzld.piaoquan.recommend.server.service.filter.FilterParam;
import com.tzld.piaoquan.recommend.server.service.filter.FilterStrategy;
import com.tzld.piaoquan.recommend.server.util.CommonCollectionUtils;
import com.tzld.piaoquan.recommend.server.util.JSONUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

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

/**
 * @author dyp
 */
@Component
@Slf4j
public class RiskVideoStrategy implements FilterStrategy {

    @ApolloJsonValue("${risk.video.tag:[]}")
    private List<Long> riskVideoTagIds;

    /**
     * 安全测试 风险标签
     */
    @ApolloJsonValue("${testing.risk.video.tag:[]}")
    private List<Long> testingRiskVideoTagIds;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private WxVideoTagRelRepository repository;
    // 内存持久保存不淘汰
    private LoadingCache<String, Set<Long>> riskVideoCache = CacheBuilder.newBuilder()
            .maximumSize(10)
            .refreshAfterWrite(600, TimeUnit.SECONDS)
            .expireAfterWrite(600, TimeUnit.SECONDS)
            .expireAfterAccess(600, TimeUnit.SECONDS)
            .build(new CacheLoader<String, Set<Long>>() {
                @Override
                public Set<Long> load(String key) {
                    Set<Long> riskVideoIdSet = new HashSet<>();
                    if (Objects.nonNull(riskVideoTagIds) && !riskVideoTagIds.isEmpty()) {
                        List<WxVideoTagRel> rels = repository.findAllByTagIdIn(riskVideoTagIds);
//                    return CommonCollectionUtils.toSet(rels, WxVideoTagRel::getVideoId)
                        //原标签内容保留 用于实时处理
                        Set<Long> tagVideoIds = CommonCollectionUtils.toSet(rels, WxVideoTagRel::getVideoId);
                        if (Objects.nonNull(tagVideoIds) && !tagVideoIds.isEmpty()) {
                            riskVideoIdSet.addAll(tagVideoIds);
                        }
                    }
                    //改为视频list 不超过10w条
                    Set<String> videoIdSet = redisTemplate.opsForSet().members(RedisKeyConstants.Recommend.WECHAT_RISK_VIDEO_CACHE_KEY);
                    if (Objects.nonNull(videoIdSet) && !videoIdSet.isEmpty()) {
                        Set<Long> riskVideoIds = videoIdSet.stream().map(Long::parseLong).collect(Collectors.toSet());
                        if (!riskVideoIds.isEmpty()) {
                            riskVideoIdSet.addAll(riskVideoIds);
                        }
                    }
                    return riskVideoIdSet;
                }
            });

    private LoadingCache<String, Set<Long>> testingRiskVideoCache = CacheBuilder.newBuilder()
            .maximumSize(10)
            .refreshAfterWrite(600, TimeUnit.SECONDS)
            .expireAfterWrite(600, TimeUnit.SECONDS)
            .expireAfterAccess(600, TimeUnit.SECONDS)
            .build(new CacheLoader<String, Set<Long>>() {
                @Override
                public Set<Long> load(String key) {
                    Set<Long> riskVideoIdSet = new HashSet<>();
                    if (Objects.nonNull(testingRiskVideoTagIds) && !testingRiskVideoTagIds.isEmpty()) {
                        //数量有限，一次查询，后续考虑优化
                        List<WxVideoTagRel> rels = repository.findAllByTagIdIn(testingRiskVideoTagIds);
                        Set<Long> tagVideoIds = CommonCollectionUtils.toSet(rels, WxVideoTagRel::getVideoId);
                        if (Objects.nonNull(tagVideoIds) && !tagVideoIds.isEmpty()) {
                            riskVideoIdSet = tagVideoIds;
                        }
                    }
                    return riskVideoIdSet;
                }
            });

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

        if (!param.isRiskUser() && !param.isTestingRiskRegion()) {
            return param.getVideoIds();
        }

        List<Long> videoIds = param.getVideoIds();
        if (param.isRiskUser()) {
            Set<Long> riskVids = riskVideoCache.getUnchecked("");
            videoIds = videoIds.stream()
                    .filter(l -> !riskVids.contains(l))
                    .collect(Collectors.toList());
        }

        if (param.isTestingRiskRegion()) {
            Set<Long> riskVids = testingRiskVideoCache.getUnchecked("");
            videoIds = videoIds.stream()
                    .filter(l -> !riskVids.contains(l))
                    .collect(Collectors.toList());
        }

        // log.info("RiskVideoStrategy \t param={} \t before={} \t after={}",
        //         JSONUtils.toJson(param),
        //         JSONUtils.toJson(param.getVideoIds()),
        //         JSONUtils.toJson(videoIds));

        return videoIds;
    }
}
