package com.ruoyi.cms.util;

import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 * 分布式唯一 ID 生成工具类（适配 Hutool 5.7.22）
 * 生成 Long 型 ID，适配数据库 bigint 字段，无高版本方法依赖
 */
@Component
public class IdGenerator {

    // 雪花算法实例（全局单例）
    private Snowflake snowflake;

    /**
     * 初始化雪花算法（Spring 启动时执行，兼容 Hutool 5.7.22）
     * 核心：用 IP 哈希 + 随机数生成唯一机器码，避免高版本方法依赖
     */
    @PostConstruct
    public void initSnowflake() {
        long workerId = generateWorkerId();
        long dataCenterId = generateDataCenterId();
        snowflake = IdUtil.createSnowflake(workerId, dataCenterId);
        System.out.printf("雪花算法初始化成功：workerId=%d，dataCenterId=%d%n", workerId, dataCenterId);
    }

    /**
     * 生成 workerId（0-31）：基于本地 IP 哈希，避免重复
     */
    private long generateWorkerId() {
        try {
            // 获取本地 IP 地址（兼容本地开发、服务器环境）
            InetAddress localHost = InetAddress.getLocalHost();
            String ip = localHost.getHostAddress();
            // IP 哈希后取模 32，确保在 0-31 范围内
            return Math.abs(ip.hashCode()) % 32;
        } catch (UnknownHostException e) {
            // 异常降级：IP 获取失败时，用随机数生成（0-31）
            return (long) (Math.random() * 32);
        }
    }

    /**
     * 生成 dataCenterId（0-31）：基于系统信息哈希，与 workerId 组合确保唯一性
     */
    private long generateDataCenterId() {
        // 取系统主机名哈希，避免与 workerId 重复
        try {
            String hostName = InetAddress.getLocalHost().getHostName();
            return Math.abs(hostName.hashCode()) % 32;
        } catch (UnknownHostException e) {
            // 异常降级：主机名获取失败时，用随机数生成（0-31）
            return (long) (Math.random() * 32);
        }
    }

    /**
     * 生成唯一 Long 型 ID（适配数据库 bigint）
     */
    public Long generateId() {
        if (snowflake == null) {
            throw new RuntimeException("雪花算法未初始化，无法生成 ID");
        }
        return snowflake.nextId();
    }

    /**
     * 生成 ID 字符串（前端避免精度丢失时使用）
     */
    public String generateIdStr() {
        return generateId().toString();
    }
}