<?php

namespace App\Services;

/**
 * 试卷ID生成器
 * 参考行业标准 Snowflake ID 思想
 */
class PaperIdGenerator
{
    // 基准时间：2020-01-01 00:00:00 (秒)
    private const EPOCH = 1577836800;

    // 12位数字的位分配（总计约2.8万亿个容量，足够使用200年）
    // 格式：时间戳(8位) + 序列号(2位) + 随机数(2位) = 12位数字
    private const TIMESTAMP_BITS = 35; // 时间戳（秒）- 可覆盖约34年
    private const SEQUENCE_BITS = 11;  // 序列号 - 2048个值
    private const RANDOM_BITS = 11;    // 随机数 - 2048个值

    /**
     * 生成12位数字ID
     * 格式：TTTTTsssssR（时间戳+序列号+随机数）
     *
     * @return string 12位数字字符串
     */
    public static function generate(): string
    {
        // 使用时间戳（分钟）而不是秒，以减少位数
        $timestamp = intdiv(time() - self::EPOCH, 60); // 从基准时间开始的分钟数
        $timestamp &= (1 << self::TIMESTAMP_BITS) - 1; // 截取指定位数

        // 同一分钟内使用序列号递增，避免并发重复
        static $lastTimestamp = 0;
        static $sequence = 0;

        if ($timestamp == $lastTimestamp) {
            $sequence = ($sequence + 1) & ((1 << self::SEQUENCE_BITS) - 1);
            // 序列号用完，等待下一分钟
            if ($sequence == 0) {
                do {
                    $timestamp = intdiv(time() - self::EPOCH, 60);
                    $timestamp &= (1 << self::TIMESTAMP_BITS) - 1;
                } while ($timestamp <= $lastTimestamp);
            }
        } else {
            $sequence = 0;
        }

        $lastTimestamp = $timestamp;

        // 添加随机数后缀避免猜测
        $random = random_int(0, 99); // 2位随机数：00-99

        // 组合：时间戳(8位) + 序列号(2位) + 随机数(2位) = 12位数字
        // 时间戳占8位（不够前面补0）
        $timestampStr = str_pad((string)$timestamp, 8, '0', STR_PAD_LEFT);
        // 序列号占2位
        $sequenceStr = str_pad((string)$sequence, 2, '0', STR_PAD_LEFT);
        // 随机数占2位
        $randomStr = str_pad((string)$random, 2, '0', STR_PAD_LEFT);

        $id = $timestampStr . $sequenceStr . $randomStr;

        // 确保第一位不为0
        if ($id[0] === '0') {
            $id[0] = '1';
        }

        return $id;
    }

    /**
     * 验证12位数字ID格式
     *
     * @param string $id
     * @return bool
     */
    public static function validate(string $id): bool
    {
        return preg_match('/^[1-9]\d{11}$/', $id) === 1;
    }

    /**
     * 从ID提取时间戳
     *
     * @param string $id
     * @return int|null
     */
    public static function extractTimestamp(string $id): ?int
    {
        if (!self::validate($id)) {
            return null;
        }

        // 提取前8位时间戳（分钟），转换为秒
        $timestampMinutes = (int)substr($id, 0, 8);
        return $timestampMinutes * 60 + self::EPOCH;
    }

    /**
     * 批量生成不重复的ID
     *
     * @param int $count
     * @return array
     */
    public static function generateBatch(int $count): array
    {
        $ids = [];
        $attempts = 0;
        $maxAttempts = $count * 10;

        while (count($ids) < $count && $attempts < $maxAttempts) {
            $id = self::generate();
            if (!in_array($id, $ids)) {
                $ids[] = $id;
            }
            $attempts++;
        }

        return $ids;
    }
}
