package com.ycwl.basic.utils;


import com.ycwl.basic.model.snowFlake.UniqueId;
import com.ycwl.basic.model.snowFlake.UniqueIdMetaData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * @author Created by liuhongguang
 * @Description
 */
@Slf4j
@Component
public class SnowFlakeUtil {

    /**
     * 记录上一毫秒数
     */
    private static long lastTimestamp = -1L;

    /**
     * 记录毫秒内的序列，0-4095
     */
    private static long sequence = 0L;

    private static Long machineId = 1L;

    private static Long datacenterId =1L;


    public static synchronized String getId() {
        long timestamp = System.currentTimeMillis();

        // 如果当前时间小于上一次ID生成的时间戳，说明系统时钟被修改过，回退在上一次ID生成时间之前应当抛出异常！！！
        if (timestamp < lastTimestamp) {
            throw new IllegalStateException(
                    String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
        }

        //如果是同一时间生成的，则进行毫秒内序列
        if (lastTimestamp == timestamp) {
            sequence = (sequence + 1) & UniqueIdMetaData.SEQUENCE_MASK;
            //毫秒内序列溢出
            if (sequence == 0) {
                //阻塞到下一个毫秒,获得新的时间戳
                timestamp = System.currentTimeMillis();
                while (timestamp <= lastTimestamp) {
                    timestamp = System.currentTimeMillis();
                }
                return String.valueOf(timestamp);
            }
        }
        //时间戳改变，毫秒内序列重置
        else {
            sequence = 0L;
        }

        // 上次生成ID的时间截
        lastTimestamp = timestamp;

        // 移位并通过或运算组成64位ID

        return  String.valueOf(((timestamp - UniqueIdMetaData.START_TIME) << UniqueIdMetaData.TIMESTAMP_LEFT_SHIFT_BITS)
                | (datacenterId << UniqueIdMetaData.DATACENTER_SHIFT_BITS)
                | (machineId<< UniqueIdMetaData.MACHINE_SHIFT_BITS)
                | sequence);
    }
    public static Long getLongId(){
        return Long.valueOf(getId());
    }




    public UniqueId explainId(long id) {
        UniqueId uniqueId = com.ycwl.basic.utils.SnowFlakeUtil.convert(id);
        if (uniqueId == null) {
            log.error("==>  解析ID失败, ID不合法");
            return null;
        }
        return uniqueId;
    }


    public Date transTime(long time) {
        return new Date(time + UniqueIdMetaData.START_TIME);
    }


    /**
     * 唯一ID对象解析返回ID
     *
     * @param uniqueId
     * @return
     */
    public static long convert(UniqueId uniqueId) {
        long result = 0;
        try {

            result |= uniqueId.getSequence();

            result |= uniqueId.getMachineId() << UniqueIdMetaData.MACHINE_SHIFT_BITS;

            result |= uniqueId.getDatacenterId() << UniqueIdMetaData.DATACENTER_SHIFT_BITS;

            result |= uniqueId.getTimestamp() << UniqueIdMetaData.TIMESTAMP_LEFT_SHIFT_BITS;

        } catch (Exception e) {
            e.printStackTrace();
            return result;
        }
        return result;
    }


    public static UniqueId convert(long id) {
        UniqueId uniqueId = null;
        try {
            uniqueId = new UniqueId();

            uniqueId.setSequence(id & UniqueIdMetaData.SEQUENCE_MASK);

            uniqueId.setMachineId((id >>> UniqueIdMetaData.MACHINE_SHIFT_BITS) & UniqueIdMetaData.MACHINE_MASK);

            uniqueId.setDatacenterId((id >>> UniqueIdMetaData.DATACENTER_SHIFT_BITS) & UniqueIdMetaData.DATACENTER_MASK);

            uniqueId.setTimestamp((id >>> UniqueIdMetaData.TIMESTAMP_LEFT_SHIFT_BITS) & UniqueIdMetaData.TIMESTAMP_MASK);

        } catch (Exception e) {
            e.printStackTrace();
            return uniqueId;
        }
        return uniqueId;
    }
}
