/**
 * 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.distributed;

import cn.hutool.core.collection.CollectionUtil;
import com.crunii.micro.common.constants.RedisKeys;
import com.crunii.micro.common.utils.JsonUtil;
import lombok.extern.slf4j.Slf4j;
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.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * @author shenhs create 2023/5/25 18:55
 */
@Slf4j
@RefreshScope
@Component
public class DistributedSnowFlakeHandle implements InitializingBean {

	@Value("${snowFlake.maxId}")
	private int maxId;
	@Value("${snowFlake.minId}")
	private int minId;
	@Value("${snowFlake.expireTime:30}")
	private int expireTime;
	@Value("${snowFlake.refreshTime:10}")
	private int refreshTime;

	@Autowired
	private RedissonClient redissonClient;

	//	private RList<Integer> list = null;
	private RMapCache<Integer, Integer> mapCache;

	private ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(8);

	private int currWorkerId;

	@Override public void afterPropertiesSet() throws Exception {
		ArrayList<Integer> allId = new ArrayList<>(maxId);
		for(int i=1;i<=30;i++){
			allId.add(i);
		}
		this.currWorkerId = minId;
		if(this.mapCache==null){
			this.mapCache = redissonClient.getMapCache(RedisKeys.DISTRIBUTED_SNOWFLAKE_KEY);
		}
		if(this.mapCache.isEmpty()){
			int i = currWorkerId;
			setWorkerId(i);
		}else{
			Collection<Integer> workerIds = mapCache.values();

//			List<Integer> workerIds = list.readAll();
			ArrayList<Integer> disjunction = (ArrayList) CollectionUtil.disjunction(workerIds, allId);
			Integer i = disjunction.get(0);
			setWorkerId(i);
			this.currWorkerId = i;
		}

		scheduledExecutorService.scheduleWithFixedDelay(()->{
			Collection<Integer> values = mapCache.values();
			// System.out.println("每分钟维护一次雪花ID数据，当前ID："+currWorkerId);
			if(values.isEmpty() || !values.contains(currWorkerId)){
				log.error("currWorkerId已丢失{}",JsonUtil.getJsonString(values));
			}
			setWorkerId(currWorkerId);
		},0,refreshTime,TimeUnit.MINUTES);
	}

	public void setWorkerId(int id){
		this.mapCache.put(id,id,expireTime, TimeUnit.MINUTES);
		DistributedSnowFlakeId.changeSnowflakeWorkerId(id);
	}


}
