
// inbox provides functions to read inboxes, create random inboxes, and to derive inboxes and sealer keys

package inbox

import "seekia/internal/cryptography/blake3"
import "seekia/internal/encoding"
import "seekia/internal/identity"
import "crypto/rand"

import "slices"
import "errors"


func GetNewRandomInbox()([10]byte, error){

	var inboxArray [10]byte

	_, err := rand.Read(inboxArray[:])
	if (err != nil) { return [10]byte{}, err }

	return inboxArray, nil
}

func GetNewRandomSecretInboxSeed()([22]byte, error){

	var newSecretInboxSeed [22]byte

	_, err := rand.Read(newSecretInboxSeed[:])
	if (err != nil) { return [22]byte{}, err }

	return newSecretInboxSeed, nil
}

func ReadInboxString(inputInbox string)([10]byte, error){

	inboxBytes, err := encoding.DecodeBase32StringToBytes(inputInbox)
	if (err != nil){
		return [10]byte{}, errors.New("ReadInboxString called with invalid inbox: " + inputInbox + ". Not Base32: " + err.Error())
	}

	if (len(inboxBytes) != 10){
		return [10]byte{}, errors.New("ReadInboxString called with invalid inbox: " + inputInbox + ". Invalid length.")
	}

	inboxArray := [10]byte(inboxBytes)

	return inboxArray, nil
}

func GetPublicInboxFromIdentityHash(inputIdentityHash [16]byte)([10]byte, error){

	identityType, err := identity.GetIdentityTypeFromIdentityHash(inputIdentityHash)
	if (err != nil) {
		identityHashHex := encoding.EncodeBytesToHexString(inputIdentityHash[:])
		return [10]byte{}, errors.New("GetPublicInboxFromIdentityHash called with invalid identity hash: " + identityHashHex) 
	}

	if (identityType != "Mate" && identityType != "Moderator"){
		return [10]byte{}, errors.New("GetPublicInboxFromIdentityHash called with Host identity hash.")
	}

	// This sequence of bytes is the string "identitypubinbox" decoded from base32 to bytes
	hashInputSuffix := []byte{64, 200, 217, 162, 120, 125, 2, 134, 133, 215}

	hashInput := slices.Concat(inputIdentityHash[:], hashInputSuffix)

	inboxBytes, err := blake3.GetBlake3HashAsBytes(10, hashInput)
	if (err != nil) { return [10]byte{}, err }

	inboxArray := [10]byte(inboxBytes)

	return inboxArray, nil
}

// Messages sent to a user's public inbox use a doublesealedkeys sealer key that is derived from the user's identity hash
func GetPublicInboxSealerKeyFromIdentityHash(inputIdentityHash [16]byte)([32]byte, error){

 	identityType, err := identity.GetIdentityTypeFromIdentityHash(inputIdentityHash)
	if (err != nil) {
		inputIdentityHashHex := encoding.EncodeBytesToHexString(inputIdentityHash[:])
		return [32]byte{}, errors.New("GetPublicInboxSealerKeyFromIdentityHash called with invalid identity hash: " + inputIdentityHashHex)
	}

	if (identityType != "Mate" && identityType != "Moderator"){
		return [32]byte{}, errors.New("GetPublicInboxSealerKeyFromIdentityHash called with Host identityType identity hash.")
	}

	// This sequence of bytes is the string "identityhashpublicinboxsealerkey" decoded from base32 to bytes
	hashInputSuffix := []byte{64, 200, 217, 162, 120, 56, 36, 119, 208, 43, 64, 144, 208, 186, 242, 32, 22, 72, 168, 152}

	hashInput := slices.Concat(inputIdentityHash[:], hashInputSuffix)

	doubleSealedKeysSealerKey, err := blake3.GetBlake3HashAsBytes(32, hashInput)
	if (err != nil) { return [32]byte{}, err }

	doubleSealedKeysSealerKeyArray := [32]byte(doubleSealedKeysSealerKey)

	return doubleSealedKeysSealerKeyArray, nil
}


// Outputs:
//	-[10]byte: Secret inbox
//	-[32]byte: Secret inbox doubleSealedKeys sealer key
//	-error
func GetSecretInboxAndSealerKeyFromSecretInboxSeed(inputSecretInboxSeed [22]byte)([10]byte, [32]byte, error){

	secretInboxHashInput := append(inputSecretInboxSeed[:], 1)
	sealerKeyHashInput := append(inputSecretInboxSeed[:], 2)

	secretInbox, err := blake3.GetBlake3HashAsBytes(10, secretInboxHashInput)
	if (err != nil) { return [10]byte{}, [32]byte{}, err }

	secretInboxArray := [10]byte(secretInbox)

	sealerKey, err := blake3.GetBlake3HashAsBytes(32, sealerKeyHashInput)
	if (err != nil) { return [10]byte{}, [32]byte{}, err }

	sealerKeyArray := [32]byte(sealerKey)

	return secretInboxArray, sealerKeyArray, nil
}



