package tokens

import (
	"crypto/rand"
	"crypto/sha256"
	"encoding/hex"
	"errors"
)

// Default hash algorithm for guardian is sha256
const (
	DefaultHashAlgorithm = "sha256"
	DefaultSecretLength  = 20
)

// DefaultTokenGenerator is a global, shared instance of a token generator
var DefaultTokenGenerator = &TokenGenerator{
	Length:        DefaultSecretLength,
	HashAlgorithm: DefaultHashAlgorithm,
}

// TokenGenerator implements AccessTokenGen and AuthorizeTokenGen
type TokenGenerator struct {
	Length        int
	HashAlgorithm string
}

// GenerateSecret reads from crypto.Random and returns hexadecimal string value
func (t *TokenGenerator) GenerateSecret() (secret string, bytes []byte, err error) {
	bytes = make([]byte, t.Length)
	_, err = rand.Read(bytes)
	if err != nil {
		return
	}

	secret = hex.EncodeToString(bytes)
	return
}

// HashSecret hashes secret with configured algorithm. One of secret or secretBytes is required.
func (t *TokenGenerator) HashSecret(secret string, secretBytes []byte) (secretHash string, secretHashBytes []byte, err error) {
	if (secret == "") == (secretBytes == nil) {
		err = errors.New("TokenGenerator: one of secret or secretBytes is required")
		return
	}

	if secret != "" {
		secretBytes, err = hex.DecodeString(secret)
		if err != nil {
			return
		}
	}

	hasher := sha256.New()
	_, err = hasher.Write(secretBytes)
	if err != nil {
		return
	}

	secretHashBytes = hasher.Sum(nil)
	secretHash = hex.EncodeToString(secretHashBytes)
	return
}
