package com.beagle.base.common.cache.caffeine;


import cn.hutool.core.collection.CollUtil;
import com.beagle.base.bean.vo.BasePointVO;
import com.beagle.base.bean.vo.BasePointsPropertiesNewParam;
import com.beagle.base.bean.vo.BasePointsPropertiesParam;
import com.beagle.base.common.contant.CacheConstants;
import com.beagle.base.common.contant.CodeEnum;
import com.beagle.base.common.exception.BeagleException;
import com.beagle.base.service.BaseService;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.CacheLoader;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.rtdb.model.FullPoint;
import com.rtdb.model.MinPoint;
import lombok.AllArgsConstructor;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.springframework.cache.CacheManager;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Configuration
@AllArgsConstructor
public class CacheConfig {

    @Resource
    private BaseService baseService;
    @Bean
    public CacheLoader<Object, Object> cacheLoader() {
        return new CacheLoader<Object, Object>() {
            @Override
            public Object load(Object key) throws Exception {
                System.out.println(key + "缓存为空时，初始化加载数据");
                // 通过key的前缀，比如user_来区分不同的缓存名称类型，来做对应的初始化操作
                if (key.toString().startsWith(CacheConstants.TAG_PREFIX)) {
                    // 用户信息
                    // 获取userId
                    String tag = key.toString().substring(key.toString().indexOf("_") + 1);
                    // 从数据库中获取值
                    BasePointsPropertiesNewParam basePointsPropertiesNewParam = new BasePointsPropertiesNewParam();
                    basePointsPropertiesNewParam.setTagName(new String[]{tag});
                    List<MinPoint> pointsPropertiesTags = baseService.getPointsPropertiesTags(basePointsPropertiesNewParam);
                    if (CollUtil.isNotEmpty(pointsPropertiesTags)) {
                        MinPoint minPoint = pointsPropertiesTags.get(0);
                        return minPoint.getId();
                    }
                    return null;
                }else if (key.toString().startsWith(CacheConstants.POINT_PREFIX)){
                    // 用户信息
                    // 获取userId
                    String id = key.toString().substring(key.toString().indexOf("_") + 1);
                    // 从数据库中获取值
                    BasePointsPropertiesParam basePointsPropertiesParam = new BasePointsPropertiesParam();
                    basePointsPropertiesParam.setIds(new int[]{Integer.parseInt(id)});
                    List<FullPoint> fullPointList = baseService.getPointsProperties(basePointsPropertiesParam);
                    if (CollUtil.isNotEmpty(fullPointList)) {
                        FullPoint fullPoint = fullPointList.get(0);
                        BasePointVO basePointVO = new BasePointVO();
                        basePointVO.setId(fullPoint.getBasePoint().getId());
                        basePointVO.setTag(fullPoint.getBasePoint().getTag());
                        basePointVO.setType(fullPoint.getBasePoint().getType());
                        return basePointVO;
                    }
                    return null;
                }
                else {
                    return null;
                }
            }

            @Override
            public @Nullable Object reload(@NonNull Object key, @NonNull Object oldValue) throws Exception {
                // 过期重新加载数据
                System.out.println(key + "过期重新加载数据");
                // 通过key的前缀，比如user_来区分不同的缓存名称类型，来做对应的初始化操作
                if (key.toString().startsWith(CacheConstants.TAG_PREFIX)) {
                    // 用户信息
                    // 获取userId
                    String tag = key.toString().substring(key.toString().indexOf("_") + 1);
                    // 从数据库中获取值
                    BasePointsPropertiesNewParam basePointsPropertiesNewParam = new BasePointsPropertiesNewParam();
                    basePointsPropertiesNewParam.setTagName(new String[]{tag});
                    List<MinPoint> pointsPropertiesTags = baseService.getPointsPropertiesTags(basePointsPropertiesNewParam);
                    if (CollUtil.isNotEmpty(pointsPropertiesTags)) {
                        MinPoint minPoint = pointsPropertiesTags.get(0);
                        return minPoint.getId();
                    }
                    return null;
                }else if (key.toString().startsWith(CacheConstants.POINT_PREFIX)){
                    // 用户信息
                    // 获取userId
                    String id = key.toString().substring(key.toString().indexOf("_") + 1);
                    // 从数据库中获取值
                    BasePointsPropertiesParam basePointsPropertiesParam = new BasePointsPropertiesParam();
                    basePointsPropertiesParam.setIds(new int[]{Integer.parseInt(id)});
                    List<FullPoint> fullPointList = baseService.getPointsProperties(basePointsPropertiesParam);
                    if (CollUtil.isNotEmpty(fullPointList)) {
                        FullPoint fullPoint = fullPointList.get(0);
                        BasePointVO basePointVO = new BasePointVO();
                        basePointVO.setId(fullPoint.getBasePoint().getId());
                        basePointVO.setTag(fullPoint.getBasePoint().getTag());
                        basePointVO.setType(fullPoint.getBasePoint().getType());
                        return basePointVO;
                    }
                    return null;
                }
                else {
                    return null;
                }
            }
        };
    }

    @Bean(name = "loadingCache")
    @Primary // 定义bean的加载顺序为第一个
    public LoadingCache<Object, Object> loadingCache() {
        return caffeine().build(cacheLoader());
    }

    @Bean(name = "caffeineCache")
    public Cache<Object, Object> cache(){
        return noRefreshcaffeine().build();
    }
    @Bean
    public CacheManager cacheManager() {
        CaffeineCacheManager cacheManager = new CaffeineCacheManager();
        cacheManager.setCaffeine(caffeine());
        cacheManager.setCacheLoader(cacheLoader());
        cacheManager.setCacheNames(Arrays.asList("myCache", "myCache2", "user","userRule"));
        cacheManager.setAllowNullValues(true);
        return cacheManager;
    }

    @Bean(name = "caffeine")
    public Caffeine<Object, Object> caffeine() {
        return Caffeine.newBuilder()
                // 设置过期重新刷新时间，超过该时间后，接口调用会自动去调用reload方法重新获取数据
                .refreshAfterWrite(10L, TimeUnit.MINUTES)
                .maximumSize(10000)
                .initialCapacity(100)
                .softValues()
                // 设置过期时间，超过后，缓存的值会被删除，下次调用后，因为缓存中没有值了，这时候会调用load方法，重新获取数据
                .expireAfterWrite(Long.MAX_VALUE, TimeUnit.NANOSECONDS) // 永不过期
                ;
    }

    @Bean(name = "noRefreshCaffeine")
    public Caffeine<Object, Object> noRefreshcaffeine() {
        return Caffeine.newBuilder()
                // 设置过期重新刷新时间，超过该时间后，接口调用会自动去调用reload方法重新获取数据
                .maximumSize(1000)
                .initialCapacity(100)
                .softValues()
                // 设置过期时间，超过后，缓存的值会被删除，下次调用后，因为缓存中没有值了，这时候会调用load方法，重新获取数据
                .expireAfterWrite(10L, TimeUnit.SECONDS);
    }
}
