package com.fs.utils;

import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 短码生成工具类 - 高并发、高唯一性短码生成器
 * 修复版本：解决数组越界和线程获取问题
 *
 * @author ToolKit
 * @version 1.0.2
 */
public final class ShortCodeGeneratorUtils {

    // 私有构造器，防止实例化
    private ShortCodeGeneratorUtils() {
        throw new AssertionError("Cannot instantiate utility class");
    }

    /**
     * 字符集定义枚举
     */
    public enum CharsetType {

        /** URL安全字符集（推荐） */
        URL_SAFE("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");

        private final String chars;

        CharsetType(String chars) {
            this.chars = chars;
        }

        public String getChars() {
            return chars;
        }

        public char[] getCharArray() {
            return chars.toCharArray();
        }

        public int size() {
            return chars.length();
        }
    }

    // 默认配置
    private static final CharsetType DEFAULT_CHARSET = CharsetType.URL_SAFE;

    // 单例实例（延迟加载）
    private static class InstanceHolder {
        static final ShortCodeGenerator INSTANCE = new ShortCodeGenerator(DEFAULT_CHARSET);
    }

    /**
     * 获取默认生成器实例
     */
    public static ShortCodeGenerator getInstance() {
        return InstanceHolder.INSTANCE;
    }

    /**
     * 获取指定字符集的生成器实例
     */
    public static ShortCodeGenerator getInstance(CharsetType charsetType) {
        return new ShortCodeGenerator(charsetType);
    }

    /**
     * 快速生成8位短码（使用默认配置）
     */
    public static String generate8() {
        return getInstance().generate8CharCode();
    }

    /**
     * 快速生成6位短码（使用默认配置）
     */
    public static String generate6() {
        return getInstance().generate6CharCode();
    }

    /**
     * 快速生成指定长度短码（使用默认配置）
     */
    public static String generate(int length) {
        return getInstance().generateCode(length);
    }

    /**
     * 短码生成器核心实现 - 完全修复版本
     */
    public static class ShortCodeGenerator {

        private final char[] charset;
        private final int charsetSize;
        private final AtomicLong counter = new AtomicLong(0);
        private volatile long lastTimestamp = 0;
        private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
        private final SecureRandom secureRandom;
        private static final long PROCESS_ID = getProcessId();

        /**
         * 使用默认字符集创建生成器
         */
        public ShortCodeGenerator() {
            this(DEFAULT_CHARSET);
        }

        /**
         * 使用指定字符集创建生成器
         */
        public ShortCodeGenerator(CharsetType charsetType) {
            this.charset = charsetType.getCharArray();
            this.charsetSize = charsetType.size();
            this.secureRandom = new SecureRandom();
            // 初始化安全随机数生成器
            secureRandom.nextBytes(new byte[16]);
        }

        /**
         * 生成8位短码
         */
        public String generate8CharCode() {
            return generateCode(8);
        }

        /**
         * 生成6位短码
         */
        public String generate6CharCode() {
            return generateCode(6);
        }

        /**
         * 生成指定长度短码
         */
        public String generateCode(int length) {
            validateLength(length);

            try {
                // 组合多种生成策略降低碰撞概率
                String codeByTime = generateByTimestamp(length);
                String codeByHash = generateByHash(length);

                return mixAndFinalize(codeByTime, codeByHash, length);
            } catch (Exception e) {
                // 如果任何方法失败，使用安全的降级方案
                return generateSafeFallbackCode(length);
            }
        }

        /**
         * 批量生成短码
         */
        public String[] generateBatch(int count, int length) {
            validateLength(length);

            String[] codes = new String[count];

            for (int i = 0; i < count; i++) {
                codes[i] = generateCode(length);
            }

            return codes;
        }

        /**
         * 获取字符集大小
         */
        public int getCharsetSize() {
            return charsetSize;
        }

        /**
         * 获取字符集
         */
        public String getCharsetString() {
            return new String(charset);
        }

        /**
         * 验证长度参数
         */
        private void validateLength(int length) {
            if (length < 4 || length > 16) {
                throw new IllegalArgumentException("Length must be between 4 and 16");
            }
        }

        /**
         * 安全的降级生成方案
         */
        private String generateSafeFallbackCode(int length) {
            char[] result = new char[length];
            ThreadLocalRandom random = ThreadLocalRandom.current();

            for (int i = 0; i < length; i++) {
                // 使用安全的随机数生成，确保索引为正数
                int index = random.nextInt(charsetSize);
                result[i] = charset[index];
            }

            return new String(result);
        }

        /**
         * 基于时间戳生成 - 修复线程ID获取问题
         */
        private String generateByTimestamp(int length) {
            long currentTime = System.currentTimeMillis();
            long sequence;

            lock.writeLock().lock();
            try {
                if (currentTime == lastTimestamp) {
                    sequence = counter.incrementAndGet();
                } else {
                    lastTimestamp = currentTime;
                    counter.set(0);
                    sequence = 0;
                }
            } finally {
                lock.writeLock().unlock();
            }

            ThreadLocalRandom random = ThreadLocalRandom.current();
            long randomPart = random.nextLong();

            // 获取当前线程ID
            long threadId = Thread.currentThread().getId();

            // 组合各种熵源
            long combined = currentTime ^ (sequence << 16) ^ randomPart;
            combined ^= System.nanoTime();
            combined ^= (PROCESS_ID << 48);
            combined ^= (threadId << 32);

            // 确保为正数
            combined = Math.abs(combined);
            if (combined == Long.MIN_VALUE) {
                combined = Long.MAX_VALUE; // 处理边界情况
            }

            return convertToBaseSafe(combined, length);
        }

        /**
         * 基于哈希算法生成 - 修复线程ID获取问题
         */
        private String generateByHash(int length) {
            try {
                MessageDigest md = MessageDigest.getInstance("SHA-256");

                // 使用多个熵源确保唯一性
                StringBuilder entropy = new StringBuilder();
                entropy.append(System.nanoTime())
                        .append(Thread.currentThread().getId())  // 修复这里
                        .append(System.identityHashCode(this))
                        .append(secureRandom.nextLong())
                        .append(counter.get())
                        .append(Runtime.getRuntime().freeMemory());

                byte[] hash = md.digest(entropy.toString().getBytes());

                // 使用BigInteger避免负数和溢出问题
                BigInteger bigInt = new BigInteger(1, hash); // 正数模式
                BigInteger modValue = BigInteger.valueOf(charsetSize).pow(length);

                // 取模确保值在范围内
                BigInteger result = bigInt.mod(modValue);

                return convertBigIntegerToBase(result, length);

            } catch (NoSuchAlgorithmException e) {
                // 降级方案：使用增强随机数
                return generateEnhancedRandomCode(length);
            }
        }

        /**
         * 增强随机数生成
         */
        private String generateEnhancedRandomCode(int length) {
            char[] result = new char[length];

            for (int i = 0; i < length; i++) {
                // 使用安全的随机索引生成
                int index = secureRandom.nextInt(charsetSize);
                result[i] = charset[index];
            }

            return new String(result);
        }

        /**
         * 安全的进制转换 - 完全修复版本
         */
        private String convertToBaseSafe(long number, int length) {
            char[] result = new char[length];

            // 确保number为正数
            long temp = Math.abs(number);
            if (temp == 0) {
                temp = System.nanoTime() & 0x7FFFFFFF; // 使用纳秒时间作为备用值
            }

            // 基本转换
            for (int i = length - 1; i >= 0; i--) {
                long remainder = temp % charsetSize;
                int index = (int) remainder;

                // 确保索引在有效范围内
                if (index < 0) {
                    index = (int) Math.abs(remainder);
                }
                index = index % charsetSize;

                result[i] = charset[index];
                temp = temp / charsetSize;
            }

            return new String(result);
        }

        /**
         * BigInteger版本的安全进制转换
         */
        private String convertBigIntegerToBase(BigInteger number, int length) {
            char[] result = new char[length];
            BigInteger base = BigInteger.valueOf(charsetSize);
            BigInteger temp = number;

            // 确保temp为正数
            if (temp.signum() < 0) {
                temp = temp.abs();
            }

            for (int i = length - 1; i >= 0; i--) {
                BigInteger[] divResult = temp.divideAndRemainder(base);
                int index = divResult[1].intValue();

                // 确保索引为正数且在范围内
                if (index < 0) {
                    index = -index;
                }
                index = index % charsetSize;

                result[i] = charset[index];
                temp = divResult[0];
            }

            return new String(result);
        }

        /**
         * 混合并最终化代码
         */
        private String mixAndFinalize(String code1, String code2, int length) {
            char[] result = new char[length];

            for (int i = 0; i < length; i++) {
                char c1 = code1.charAt(i % code1.length());
                char c2 = code2.charAt((i + 1) % code2.length());

                // 使用安全的混合方法
                int mixed = safeMixChars(c1, c2, i);
                result[i] = charset[mixed];
            }

            return new String(result);
        }

        /**
         * 安全的字符混合
         */
        private int safeMixChars(char c1, char c2, int position) {
            long l1 = (long) c1;
            long l2 = (long) c2;

            // 使用不同的混合策略，但都确保结果为非负数
            long mixedLong;
            switch (position % 4) {
                case 0:
                    mixedLong = (l1 + l2 * 31L) % charsetSize;
                    break;
                case 1:
                    mixedLong = (l1 ^ l2) % charsetSize;
                    break;
                case 2:
                    mixedLong = (l1 * 17L + l2) % charsetSize;
                    break;
                default:
                    mixedLong = (l1 * 3L + l2 * 7L) % charsetSize;
                    break;
            }

            // 确保结果为正数
            int mixed = (int) Math.abs(mixedLong) % charsetSize;
            return mixed;
        }

        /**
         * 获取进程ID
         */
        private static long getProcessId() {
            try {
                String processName = java.lang.management.ManagementFactory
                        .getRuntimeMXBean()
                        .getName();
                String pidStr = processName.split("@")[0];
                return Long.parseLong(pidStr) & 0xFFFF; // 限制范围
            } catch (Exception e) {
                // 返回备用值
                return Thread.currentThread().getId() & 0xFFFF;
            }
        }
    }
}
