import crypto from "crypto"

export namespace uuidv7 {
    export function generate() {
        // random bytes
        const value = new Uint8Array(16)
        crypto.getRandomValues(value)

        // current timestamp in ms
        const timestamp = BigInt(Date.now())

        // timestamp
        value[0] = Number((timestamp >> 40n) & 0xffn)
        value[1] = Number((timestamp >> 32n) & 0xffn)
        value[2] = Number((timestamp >> 24n) & 0xffn)
        value[3] = Number((timestamp >> 16n) & 0xffn)
        value[4] = Number((timestamp >> 8n) & 0xffn)
        value[5] = Number(timestamp & 0xffn)

        // version and variant
        value[6] = (value[6] & 0x0f) | 0x70
        value[8] = (value[8] & 0x3f) | 0x80

        // Convert to UUID string format
        return (
            `${value[0].toString(16).padStart(2, "0")}${value[1]
                .toString(16)
                .padStart(2, "0")}${value[2]
                .toString(16)
                .padStart(2, "0")}${value[3].toString(16).padStart(2, "0")}-` +
            `${value[4].toString(16).padStart(2, "0")}${value[5]
                .toString(16)
                .padStart(2, "0")}-` +
            `${value[6].toString(16).padStart(2, "0")}${value[7]
                .toString(16)
                .padStart(2, "0")}-` +
            `${value[8].toString(16).padStart(2, "0")}${value[9]
                .toString(16)
                .padStart(2, "0")}-` +
            `${value[10].toString(16).padStart(2, "0")}${value[11]
                .toString(16)
                .padStart(2, "0")}${value[12]
                .toString(16)
                .padStart(2, "0")}${value[13]
                .toString(16)
                .padStart(2, "0")}${value[14]
                .toString(16)
                .padStart(2, "0")}${value[15].toString(16).padStart(2, "0")}`
        )
    }

    export function getDate(uuid: string) {
        const regex =
            /^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i
        if (!regex.test(uuid)) throw new Error("Invalid UUID, not v7")
        const cleanUuid = uuid.replace(/-/g, "")
        const timestampHex = cleanUuid.slice(0, 12)
        const timestamp = parseInt(timestampHex, 16)

        return new Date(timestamp)
    }
}
