package kmiputil

import (
	"encoding/binary"
	"encoding/hex"
	"strings"

	"github.com/ansel1/merry"
)

var ErrInvalidHexString = merry.New("invalid hex string")

func DecodeUint32(b []byte) uint32 {
	// pad to 4 bytes with leading zeros
	return binary.BigEndian.Uint32(pad(b, 4))
}

func DecodeUint64(b []byte) uint64 {
	// pad to 8 bytes with leading zeros
	return binary.BigEndian.Uint64(pad(b, 8))
}

func pad(b []byte, l int) []byte {
	if len(b) < l {
		b2 := make([]byte, l)
		copy(b2[l-len(b):], b)
		b = b2
	}

	return b
}

// ParseHexValue attempts to parse a string formatted as a hex value
// as described in the KMIP Profiles spec, in the "Hex representations" section.
//
// If the string doesn't start with the required prefix "0x", it is assumed the string
// is not a hex representation, and nil, nil is returned.
//
// An ErrInvalidHexString is returned if the hex parsing fails.
// If the max argument is >0, ErrInvalidHexString is returned if the number of bytes parsed
// is greater than max, ignoring leading zeros.  All bytes parsed are returned (including
// leading zeros).
func ParseHexValue(s string, max int) ([]byte, error) {
	if !strings.HasPrefix(s, "0x") {
		return nil, nil
	}

	b, err := hex.DecodeString(s[2:])
	if err != nil {
		return nil, merry.WithCause(ErrInvalidHexString, err).Append(err.Error())
	}

	if max > 0 {
		l := len(b)
		// minus leading zeros
		for i := 0; i < len(b) && b[i] == 0; i++ {
			l--
		}

		if l > max {
			return nil, merry.Appendf(ErrInvalidHexString, "must be %v bytes", max)
		}
	}

	return b, nil
}
