package oauth2

import (
	"crypto/rand"
	"math/big"
)

const (
	// Valid characters for client IDs and secrets for Basic Authentication scheme without colon char
	// https://datatracker.ietf.org/doc/html/rfc2617#section-2
	validClientCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
	clientIDLength        = 64
	clientSecretLength    = 128
)

// NewClientID returns a randomized character client ID for the device flow.
func NewClientID() string {
	return randomString(clientIDLength, validClientCharacters)
}

// NewClientSecret returns a randomized character client secret for the device flow.
func NewClientSecret() string {
	return randomString(clientSecretLength, validClientCharacters)
}

const (
	// Valid characters for user codes
	// Remove vowels to avoid randomly creating words
	// https://datatracker.ietf.org/doc/html/rfc8628#section-6.1
	validUserCharacters = "BCDFGHJKLMNPQRSTVWXZ123456789"
	// The default length of user codes
	userCodeLength = 8

	// Valid characters for device codes
	validDeviceCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.-"
	// The default length of device codes
	deviceCodeLength = 150
)

// NewUserCode returns a randomized character user code for the device flow.
func NewUserCode() string {
	code := randomString(userCodeLength, validUserCharacters)
	return code[:4] + "-" + code[4:]
}

// NewDeviceCode returns a randomized character device code for the device flow.
func NewDeviceCode() string {
	return randomString(deviceCodeLength, validDeviceCharacters)
}

func randomString(length int, validCharacters string) string {
	v := big.NewInt(int64(len(validCharacters)))
	bytes := make([]byte, length)
	for i := 0; i < length; i++ {
		c, _ := rand.Int(rand.Reader, v)
		bytes[i] = validCharacters[c.Int64()]
	}
	return string(bytes)
}

const (
	accessTokenPrefix  = "ticloud_oa_"
	refreshTokenPrefix = "ticloud_or_"
	tokenLength        = 128
)

func NewAccessToken() string {
	return accessTokenPrefix + randomString(tokenLength, validClientCharacters)
}

func NewRefreshToken() string {
	return refreshTokenPrefix + randomString(tokenLength, validClientCharacters)
}

const codeLength = 30

func NewAuthorizationCode() string {
	return randomString(codeLength, validClientCharacters)
}
