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.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 lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author dyp
 */
@Component
@Slf4j
public class SecurityStrategy implements FilterStrategy {
    @Value("#{'${block.hotscenetype.list:}'.split(',')}")
    private Set<Long> excludeScenes;
    @ApolloJsonValue("${video.filter.city.tagid.json:{}}")
    private Map<String, List<Long>> videoFilterCityTagIdMap;
    @Value("${securityAbExpCode:625}")
    private String securityAbExpCode;
    @Value("${securityGlobalSwitch:false}")
    private boolean securityGlobalSwitch;

    @Value("${content.security.new.filter.switch:false}")
    private boolean newContentSecurityFilterSwitch;

    @Autowired
    private WxVideoTagRelRepository wxVideoTagRelRepository;

    @Resource
    private BlacklistContainer blacklistContainer;

    // 内存持久保存不淘汰
    private LoadingCache<String, Set<Long>> videoCache = CacheBuilder.newBuilder()
            .maximumSize(100)
            .refreshAfterWrite(60, TimeUnit.SECONDS)
            .expireAfterWrite(60, TimeUnit.SECONDS)
            .expireAfterAccess(60, TimeUnit.SECONDS)
            .build(new CacheLoader<String, Set<Long>>() {
                @Override
                public Set<Long> load(String cityCode) {
                    if (MapUtils.isEmpty(videoFilterCityTagIdMap)) {
                        return new HashSet<>();
                    }
                    List<Long> tagIds = videoFilterCityTagIdMap.get(cityCode);
                    if (CollectionUtils.isEmpty(tagIds)) {
                        return new HashSet<>();
                    }
                    List<WxVideoTagRel> rels = wxVideoTagRelRepository.findAllByTagIdIn(tagIds);
                    return CommonCollectionUtils.toSet(rels, WxVideoTagRel::getVideoId);
                }
            });

    @PostConstruct
    public void init() {
        if (MapUtils.isEmpty(videoFilterCityTagIdMap)) {
            return;
        }
        for (String cityCode : videoFilterCityTagIdMap.keySet()) {
            videoCache.getUnchecked(cityCode);
        }
        log.info("newContentSecurityFilterSwitch: {}", newContentSecurityFilterSwitch);
    }

    @Override
    public List<Long> filter(FilterParam param) {

        if (param == null) {
            return Collections.emptyList();
        }
        if (CollectionUtils.isEmpty(param.getVideoIds())) {
            return param.getVideoIds();
        }

        boolean hit = securityGlobalSwitch
                || CommonCollectionUtils.contains(param.getAbExpCodes(), securityAbExpCode);
        if (!hit) {
            return param.getVideoIds();
        }

        if (newContentSecurityFilterSwitch) {
            return blacklistContainer.filterUnsafeVideoByUser(param.getVideoIds(), param.getUid(), param.getHotSceneType(),
                    param.getCityCode(), param.getClientIp(), param.getMid(), "recommend", param.getAppType());
        }

        if (CollectionUtils.isEmpty(excludeScenes)
                || !CommonCollectionUtils.contains(excludeScenes, param.getHotSceneType())) {
            log.info("old filter cityCodeAndScene filter");
            if (MapUtils.isEmpty(videoFilterCityTagIdMap)
                    || !videoFilterCityTagIdMap.containsKey(param.getCityCode())) {
                return param.getVideoIds();
            }

            Set<Long> filterVideos = videoCache.getUnchecked(param.getCityCode());
            if (CollectionUtils.isEmpty(filterVideos)) {
                return param.getVideoIds();
            }

            List<Long> result = param.getVideoIds().stream()
                    .filter(l -> !filterVideos.contains(l))
                    .collect(Collectors.toList());

            return result;
        }
        return param.getVideoIds();


    }
}
