// Package id provides unique ID generation using the Sonyflake algorithm
package id

import (
	"fmt"
	"log"
	"math/rand"
	"strconv"
	"time"

	"github.com/sony/sonyflake"
)

var sf *sonyflake.Sonyflake

const maxMachineID = 1<<16 - 1

func init() {
	// Initialize random source for machine ID generation
	// Note: There is a small risk of machineID collisions if multiple
	// instances are started within the same microsecond
	r := rand.New(rand.NewSource(time.Now().UnixMicro()))

	st := sonyflake.Settings{
		StartTime: time.Date(2022, 1, 1, 0, 0, 0, 0, time.UTC),
		MachineID: func() (uint16, error) {
			return uint16(r.Intn(maxMachineID)), nil
		},
		CheckMachineID: nil,
	}

	sf = sonyflake.NewSonyflake(st)
	if sf == nil {
		log.Panicf("failed to initialize sonyflake")
	}
}

// Str returns a string representation of a unique Sonyflake ID.
// It panics if ID generation fails.
func Str() string {
	id, err := sf.NextID()
	if err != nil {
		panic(fmt.Sprintf("failed to generate sonyflake ID: %v", err))
	}
	return strconv.FormatUint(id, 10)
}

// UInt64 returns a uint64 unique Sonyflake ID.
// It panics if ID generation fails.
func UInt64() uint64 {
	id, err := sf.NextID()
	if err != nil {
		panic(fmt.Sprintf("failed to generate sonyflake ID: %v", err))
	}
	return id
}
