/**
 * Copyright 2008-2009. Chongqing Communications Industry Services Co.,Ltd Information Technology Branch. All rights reserved.
 * <a>http://www.crunii.com</a>
 */
package com.crunii.micro.core.cache;

import com.crunii.micro.common.constants.CommonConstants;
import com.crunii.micro.common.constants.RedisKeys;
import com.crunii.micro.domain.entity.main.TsmPropertyValue;
import com.crunii.micro.domain.repo.main.TsmPropertyValueRepo;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RList;
import org.redisson.api.RMapCache;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * @author shenhs create 2023/5/24 10:37
 */
@Slf4j
@Component
public class TsmPropertyCache implements InitializingBean {

	@Autowired
	private RedissonClient redisson;
	@Autowired
	private TsmPropertyValueRepo repo;

	// 这是一个三层结构：propCode-> valueCode-> valueName
	private RMapCache<String, Map<String, String>> propertyCache = null;
	private RList<TsmPropertyValue> propertyListCache = null;

	private Cache<String, Map<String, String>> timedCache = CacheBuilder.newBuilder().expireAfterWrite(60*3, TimeUnit.SECONDS).build();

	@Override public void afterPropertiesSet() {
		if (propertyListCache == null) {
//			propertyCache = redisson.getMapCache(RedisKeys.TSM_PROPERTY_CACHE_KEY);
			propertyListCache = redisson.getList(RedisKeys.TSM_PROPERTY_VALUE_CACHE_KEY);
		}
		if (propertyListCache.isEmpty()) {
			load();
		}
	}

	private void load() {
		List<TsmPropertyValue> all = repo.findAll();
		propertyListCache.addAll(all);
		/*
		Map<String, List<TsmPropertyValue>> collect = all.stream().collect(Collectors.groupingBy(TsmPropertyValue::getPropCode));
		Set<String> keySet = collect.keySet();
		Map<String,Map<String,String>> redisData = new HashMap<>();
		// 组装出三层结构：propCode-> valueCode-> valueName
		keySet.forEach(key->{
			List<TsmPropertyValue> tsmPropertyValues = collect.get(key);
			Map<String, String> propItems = tsmPropertyValues.stream()
					.collect(Collectors.toMap(TsmPropertyValue::getValueCode, TsmPropertyValue::getValueName));
			redisData.put(key,propItems);
		});
		// 写入缓存
		propertyCache.putAll(redisData); */

	}

	public Map<String, String> getAllValueByCode(String propCode) {
		Map<String, String> propMap = timedCache.getIfPresent(propCode);
		if (propMap == null) {
			Map<String, List<TsmPropertyValue>> collect = propertyListCache.stream().collect(Collectors.groupingBy(TsmPropertyValue::getPropCode));
			Set<String> keySet = collect.keySet();
			Map<String, Map<String, String>> localCacheData = new HashMap<>();
			// 组装出三层结构：propCode-> valueCode-> valueName
			keySet.forEach(key -> {
				List<TsmPropertyValue> tsmPropertyValues = collect.get(key);
				Map<String, String> propItems = tsmPropertyValues.stream()
						.collect(Collectors.toMap(TsmPropertyValue::getValueCode, TsmPropertyValue::getValueName));
				localCacheData.put(key, propItems);
			});
			timedCache.putAll(localCacheData);
			return localCacheData.get(propCode);
		}
		return propMap;
	}

	//filter去重方法实现类
	private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
		Set<Object> seen = ConcurrentHashMap.newKeySet();
		return t -> seen.add(keyExtractor.apply(t));
	}

	public String get(String propCode, String propValue) {
		Map<String, String> propMap = timedCache.getIfPresent(propCode);
		if (propMap == null) {
			Map<String, List<TsmPropertyValue>> collect = propertyListCache.stream().collect(Collectors.groupingBy(TsmPropertyValue::getPropCode));
			Set<String> keySet = collect.keySet();
			Map<String, Map<String, String>> localCacheData = new HashMap<>();
			// 组装出三层结构：propCode-> valueCode-> valueName
			keySet.forEach(key -> {
				List<TsmPropertyValue> tsmPropertyValues = collect.get(key).stream().filter(distinctByKey(TsmPropertyValue::getValueCode)).collect(Collectors.toList());
				Map<String, String> propItems = tsmPropertyValues.stream()
						.collect(Collectors.toMap(TsmPropertyValue::getValueCode, TsmPropertyValue::getValueName));
				localCacheData.put(key, propItems);
			});

			if (!localCacheData.containsKey(propCode)) {
				//缓存中没有则查询数据库，添加进缓存
				List<TsmPropertyValue> propertyValueList = repo.findAllByPropCodeAndState(propCode, CommonConstants.STATE_VALID);
				if (propertyValueList != null && propertyValueList.size() > 0) {
					Map<String, String> propItems = propertyValueList.stream()
							.collect(Collectors.toMap(TsmPropertyValue::getValueCode, TsmPropertyValue::getValueName));
					localCacheData.put(propCode, propItems);
				}
			}
			timedCache.putAll(localCacheData);
			return localCacheData.get(propCode).get(propValue);
//			Collection<Map<String, String>> values = propertyCache.values();
		} else {
			return propMap.get(propValue);
		}
	}

	public void reload() {
		propertyListCache.clear();
		load();
	}
}
