
// seedPhrase provides functions to read/create seed phrases, and derive seed phrase hashes

package seedPhrase

// Seed Phrase is 15 words, separated by " "
// A seed phrase hash is a 32 bytes long blake3 hash of the seed phrase unicode bytes

import "seekia/internal/wordLists"

import "seekia/internal/cryptography/blake3"

import "crypto/rand"
import "math/big"
import "errors"
import "strings"


func VerifySeedPhrase(inputSeedPhrase string)bool{

	seedPhraseCharacterCount := len(inputSeedPhrase)

	if (seedPhraseCharacterCount < 44){
		// There are 15 words, each word is at least 2 characters long
		// 15 words * 2 characters each = 30 characters
		// Each word is separated by a space
		// 30 + 14 == 44 characters
		return false
	}

	numberOfSpaces := 0

	currentNumberOfCharacters := 0

	finalIndex := seedPhraseCharacterCount - 1

	for index, character := range inputSeedPhrase{

		if (character == ' '){

			if (currentNumberOfCharacters < 2){
				// The seed phrase contains a word with less than 2 characters
				return false
			}

			currentNumberOfCharacters = 0
			numberOfSpaces += 1

		} else {
			currentNumberOfCharacters += 1
		}

		if (index == finalIndex && currentNumberOfCharacters < 2){
			// The seed phrase ends with a word containing less than 2 characters
			return false
		}
	}

	if (numberOfSpaces != 14){
		return false
	}

	return true
}

func ConvertSeedPhraseToSeedPhraseHash(inputSeedPhrase string)([32]byte, error){

	isValid := VerifySeedPhrase(inputSeedPhrase)
	if (isValid == false){
		return [32]byte{}, errors.New("ConvertSeedPhraseToSeedPhraseHash called with invalid seed phrase.")
	}

	seedPhraseBytes := []byte(inputSeedPhrase)

	seedPhraseHash, err := blake3.Get32ByteBlake3Hash(seedPhraseBytes)
	if (err != nil) { return [32]byte{}, err }

	return seedPhraseHash, nil
}


// This function is slower, only use it for generating a few seed phrases
// For many generations, use GetNewSeedPhraseFromWordList, which is faster
//Outputs:
//	-string: New seed phrase
//	-[32]byte: New seed phrase hash
//	-error
func GetNewRandomSeedPhrase(languageName string)(string, [32]byte, error){

	wordList, err := wordLists.GetWordListFromLanguage(languageName)
	if (err != nil) { return "", [32]byte{}, err }

	newSeedPhrase, newSeedPhraseHash, err := GetNewSeedPhraseFromWordList(wordList)
	if (err != nil) { return "", [32]byte{}, err }

	return newSeedPhrase, newSeedPhraseHash, nil
}

// wordList must be retrieved from internal/wordLists/wordLists.go
//Outputs:
//	-string: Seed phrase
//	-[32]byte: Seed phrase hash
//	-error
func GetNewSeedPhraseFromWordList(wordList []string)(string, [32]byte, error){

	lengthOfWordList := len(wordList)

	if (lengthOfWordList < 2048) {
		return "", [32]byte{}, errors.New("GetNewSeedPhraseFromWordList called with word list that is too short.")
	}

	upperLimitInt64 := int64(lengthOfWordList-1)
	upperLimit := big.NewInt(upperLimitInt64)

	// We use this to build the seed phrase
	var seedPhraseBuilder strings.Builder

	for i := 0; i < 15; i++ {

		randomNumber, err := rand.Int(rand.Reader, upperLimit)
		if (err != nil) { return "", [32]byte{}, err }

		wordIndex := int(randomNumber.Int64())
		randomWord := wordList[wordIndex]

		_, err = seedPhraseBuilder.WriteString(randomWord)
		if (err != nil) { return "", [32]byte{}, err }

		if (i < 14){
			// There is a space between every word, and no trailing space
			_, err := seedPhraseBuilder.WriteString(" ")
			if (err != nil) { return "", [32]byte{}, err }
		}
	}

	newSeedPhrase := seedPhraseBuilder.String()

	newSeedPhraseBytes := []byte(newSeedPhrase)

	newSeedPhraseHash, err := blake3.Get32ByteBlake3Hash(newSeedPhraseBytes)
	if (err != nil) { return "", [32]byte{}, err }

	return newSeedPhrase, newSeedPhraseHash, nil
}


