package internal

import (
	"encoding/binary"
	"time"

	"xdx.jelly/xgcl/internal"
)

// var nonceCounter atomic.Int64

// atomic.Int64 only available in go 1.19, so we make a new one.
type atomicUint64 struct {
	spin internal.SpinLock
	n    uint64
}

var nonceCounter atomicUint64

func (a *atomicUint64) LoadAndAdd(n uint64) uint64 {
	a.spin.Lock()
	defer a.spin.Unlock()
	v := a.n
	a.n += n
	return v
}

// nonce 由时间戳和单调递增的计数器组成
func Nonce() []byte {
	out := make([]byte, 16)
	binary.BigEndian.PutUint64(out, uint64(time.Now().UnixNano()))
	binary.BigEndian.PutUint64(out[8:], nonceCounter.LoadAndAdd(1))
	return out
}

// AddModBytes a = a+b as integer, a,b are bigendian and len(a) >= len(b).
func AddModBytes(a, b []byte) {
	var x uint

	x = 0
	i := len(a) - 1
	j := len(b) - 1
	for j >= 0 {
		x += uint(a[i]) + uint(b[j])
		a[i] = byte(x)
		x = x >> 8
		j--
		i--
	}
	if x == 0 {
		return
	}
	for i >= 0 {
		a[i] += 1
		if a[i] != 0 {
			break
		}
	}
}

func IncBytes(a []byte) {
	i := len(a) - 1
	for i >= 0 {
		a[i]++
		if a[i] != 0 {
			break
		}
	}
}
