
// myBroadcasts provides functions to manage a user's broadcast content
// This is content that will be broadcast or has already been broadcast
// The app will automatically broadcast the content in the background

package myBroadcasts

//TODO: Add reports and parameters
//TODO: Keep track of how many times each piece of content has been broadcast, and use that information to 
//		broadcast older content less over time
//TODO: Add functions to prune old broadcasted profiles, messages, reports, and parameters

import "seekia/internal/cryptography/csidh"
import "seekia/internal/cryptography/nacl"
import "seekia/internal/cryptography/mlkem"
import "seekia/internal/encoding"
import "seekia/internal/helpers"
import "seekia/internal/identity"
import "seekia/internal/localFilesystem"
import "seekia/internal/messaging/myChatKeys"
import "seekia/internal/messaging/readMessages"
import "seekia/internal/moderation/mySkippedContent"
import "seekia/internal/moderation/readReviews"
import "seekia/internal/moderation/reviewStorage"
import "seekia/internal/myIdentity"
import "seekia/internal/network/appNetworkType/getAppNetworkType"
import "seekia/internal/profiles/calculatedAttributes"
import "seekia/internal/profiles/myProfileExports"
import "seekia/internal/profiles/profileStorage"
import "seekia/internal/profiles/readProfiles"

import messagepack "github.com/vmihailenco/msgpack/v5"

import goFilepath "path/filepath"
import "os"
import "errors"

func InitializeMyBroadcastsFolders()error{

	userDirectory, err := localFilesystem.GetAppUserFolderPath()
	if (err != nil) { return err }

	myBroadcastsFolderpath := goFilepath.Join(userDirectory, "MyBroadcasts")

	_, err = localFilesystem.CreateFolder(myBroadcastsFolderpath)
	if (err != nil) { return err }

	profilesFolderpath := goFilepath.Join(userDirectory, "MyBroadcasts", "Profiles")
	messagesFolderpath := goFilepath.Join(userDirectory, "MyBroadcasts", "Messages")
	reportsFolderpath := goFilepath.Join(userDirectory, "MyBroadcasts", "Reports")
	parametersFolderpath := goFilepath.Join(userDirectory, "MyBroadcasts", "Parameters")

	folderpathsList := []string{profilesFolderpath, messagesFolderpath, reportsFolderpath, parametersFolderpath}

	for _, folderpath := range folderpathsList{

		_, err := localFilesystem.CreateFolder(folderpath)
		if (err != nil) { return err }

		network1Folderpath := goFilepath.Join(folderpath, "Network1")
		network2Folderpath := goFilepath.Join(folderpath, "Network2")

		_, err = localFilesystem.CreateFolder(network1Folderpath)
		if (err != nil) { return err }

		_, err = localFilesystem.CreateFolder(network2Folderpath)
		if (err != nil) { return err }
	}

	reviewsFolderpath := goFilepath.Join(userDirectory, "MyBroadcasts", "Reviews")

	_, err = localFilesystem.CreateFolder(reviewsFolderpath)
	if (err != nil) { return err }

	// We create reviews subfolders for each reviewType
	// We use subfolders so retrieval is faster
	// The speedup will be significant for moderators with tens of thousands of reviews
	// Reports do not need subfolders because users will typically create very few reports

	identityReviewsFolderpath := goFilepath.Join(userDirectory, "MyBroadcasts", "Reviews", "Identity")
	profileReviewsFolderpath := goFilepath.Join(userDirectory, "MyBroadcasts", "Reviews", "Profile")
	attributeReviewsFolderpath := goFilepath.Join(userDirectory, "MyBroadcasts", "Reviews", "Attribute")
	messageReviewsFolderpath := goFilepath.Join(userDirectory, "MyBroadcasts", "Reviews", "Message")

	folderpathsList = []string{identityReviewsFolderpath, profileReviewsFolderpath, attributeReviewsFolderpath, messageReviewsFolderpath}

	for _, folderpath := range folderpathsList{

		_, err := localFilesystem.CreateFolder(folderpath)
		if (err != nil) { return err }

		network1Folderpath := goFilepath.Join(folderpath, "Network1")
		network2Folderpath := goFilepath.Join(folderpath, "Network2")

		_, err = localFilesystem.CreateFolder(network1Folderpath)
		if (err != nil) { return err }

		_, err = localFilesystem.CreateFolder(network2Folderpath)
		if (err != nil) { return err }
	}

	return nil
}

//Outputs:
//	-bool: My Identity exists
//	-bool: Profile exists
//	-int: Profile version
//	-bool: Attribute exists
//	-string: Attribute value
//	-error
func GetAnyAttributeFromMyBroadcastProfile(myIdentityHash [16]byte, networkType byte, attribute string)(bool, bool, int, bool, string, error){

	isValid := helpers.VerifyNetworkType(networkType)
	if (isValid == false){
		networkTypeString := helpers.ConvertByteToString(networkType)
		return false, false, 0, false, "", errors.New("GetAnyAttributeFromMyBroadcastProfile called with invalid networkType: " + networkTypeString)
	}

	identityExists, profileExists, _, getAnyAttributeFunction, err := GetRetrieveAnyAttributeFromMyBroadcastProfileFunction(myIdentityHash, networkType)
	if (err != nil) { return false, false, 0, false, "", err }
	if (identityExists == false){
		return false, false, 0, false, "", nil
	}
	if (profileExists == false){
		return true, false, 0, false, "", nil
	}

	attributeExists, profileVersion, attributeValue, err := getAnyAttributeFunction(attribute)
	if (err != nil) { return false, false, 0, false, "", err }
	if (attributeExists == false){
		return true, true, 0, false, "", nil
	}
	
	return true, true, profileVersion, true, attributeValue, nil
}

//Outputs:
//	-bool: My identity exists
//	-bool: Profile exists
//	-[28]byte: Profile hash
//	-func(attributeName string)(bool, int, string, error)
//	-error
func GetRetrieveAnyAttributeFromMyBroadcastProfileFunction(myIdentityHash [16]byte, networkType byte)(bool, bool, [28]byte, func(string)(bool, int, string, error), error){

	isValid := helpers.VerifyNetworkType(networkType)
	if (isValid == false){
		networkTypeString := helpers.ConvertByteToString(networkType)
		return false, false, [28]byte{}, nil, errors.New("GetRetrieveAnyAttributeFromMyBroadcastProfileFunction called with invalid networkType: " + networkTypeString)
	}

	identityExists, _, err := myIdentity.CheckIfIdentityHashIsMine(myIdentityHash)
	if (err != nil) { return false, false, [28]byte{}, nil, err }
	if (identityExists == false){
		return false, false, [28]byte{}, nil, nil
	}
	
	profileExists, profileVersion, profileHash, _, rawProfileMap, err := GetMyNewestBroadcastProfile(myIdentityHash, networkType)
	if (err != nil) { return false, false, [28]byte{}, nil, err }
	if (profileExists == false){
		return true, false, [28]byte{}, nil, nil
	}

	getAnyAttributeFunction, err := calculatedAttributes.GetRetrieveAnyProfileAttributeIncludingCalculatedFunction(profileVersion, rawProfileMap)
	if (err != nil) { return false, false, [28]byte{}, nil, err }

	return true, true, profileHash, getAnyAttributeFunction, nil
}

//Outputs:
//	-bool: Profile found
//	-int: Profile version
//	-[28]byte: Profile hash
//	-[]byte: Profile bytes
//	-map[int]messagepack.RawMessage: Raw profile map
//	-error
func GetMyNewestBroadcastProfile(myIdentityHash [16]byte, networkType byte)(bool, int, [28]byte, []byte, map[int]messagepack.RawMessage, error){

	identityExists, _, err := myIdentity.CheckIfIdentityHashIsMine(myIdentityHash)
	if (err != nil) { return false, 0, [28]byte{}, nil, nil, err }
	if (identityExists == false){
		return false, 0, [28]byte{}, nil, nil, errors.New("GetMyNewestBroadcastProfile called with identity that is not mine.")
	}

	isValid := helpers.VerifyNetworkType(networkType)
	if (isValid == false){
		networkTypeString := helpers.ConvertByteToString(networkType)
		return false, 0, [28]byte{}, nil, nil, errors.New("GetMyNewestBroadcastProfile called with invalid networkType: " + networkTypeString)
	}

	userDirectory, err := localFilesystem.GetAppUserFolderPath()
	if (err != nil) { return false, 0, [28]byte{}, nil, nil, err }

	networkTypeString := helpers.ConvertByteToString(networkType)

	networkTypeFoldername := "Network" + networkTypeString

	profilesFolderPath := goFilepath.Join(userDirectory, "MyBroadcasts", "Profiles", networkTypeFoldername)

	broadcastProfilesList, err := localFilesystem.GetAllFilesInFolderAsList(profilesFolderPath)
	if (err != nil) { return false, 0, [28]byte{}, nil, nil, err }

	anyProfileFound := false
	newestProfileVersion := 0
	var newestProfileHash [28]byte
	newestProfileBytes := make([]byte, 0)
	newestProfileRawProfileMap := make(map[int]messagepack.RawMessage)
	newestProfileCreationTime := int64(0)

	for _, profileBytes := range broadcastProfilesList{

		ableToRead, profileHash, profileVersion, profileNetworkType, profileIdentityHash, profileCreationTime, _, rawProfileMap, err := readProfiles.ReadProfileAndHash(true, profileBytes)
		if (err != nil) { return false, 0, [28]byte{}, nil, nil, err }
		if (ableToRead == false){
			return false, 0, [28]byte{}, nil, nil, errors.New("MyBroadcasts contains invalid profile.")
		}
		if (profileNetworkType != networkType){
			return false, 0, [28]byte{}, nil, nil, errors.New("MyBroadcasts contains profile for different networkType.")
		}

		if (profileIdentityHash != myIdentityHash){
			continue
		}

		if (anyProfileFound == false || profileCreationTime > newestProfileCreationTime){

			anyProfileFound = true
			newestProfileVersion = profileVersion
			newestProfileHash = profileHash	
			newestProfileBytes = profileBytes
			newestProfileRawProfileMap = rawProfileMap
			newestProfileCreationTime = profileCreationTime
		}
	}

	if (anyProfileFound == false){
		return false, 0, [28]byte{}, nil, nil, nil
	}

	return true, newestProfileVersion, newestProfileHash, newestProfileBytes, newestProfileRawProfileMap, nil
}

// This function overwrites an identity's existing broadcast profile with current exported profile

//Outputs:
//	-bool: My identity exists
//	-[28]byte: Profile hash of new broadcast profile
//	-error
func UpdateMyBroadcastProfile(myIdentityType string, networkType byte)(bool, [28]byte, error){

	isValid := helpers.VerifyNetworkType(networkType)
	if (isValid == false){
		networkTypeString := helpers.ConvertByteToString(networkType)
		return false, [28]byte{}, errors.New("UpdateMyBroadcastProfile called with invalid networkType: " + networkTypeString)
	}

	myIdentityExists, myIdentityHash, err := myIdentity.GetMyIdentityHash(myIdentityType)
	if (err != nil) { return false, [28]byte{}, err }
	if (myIdentityExists == false){
		return false, [28]byte{}, nil
	}

	newProfileFound, exportProfileHash, newProfileBytes, _, err := myProfileExports.GetMyExportedProfile(myIdentityType, networkType)
	if (err != nil) { return false, [28]byte{}, err }
	if (newProfileFound == false){
		return false, [28]byte{}, errors.New("UpdateMyBroadcastProfile called when export profile is missing.")
	}

	ableToRead, newProfileHash, _, newProfileNetworkType, profileIdentityHash, newProfileCreationTime, _, newProfileRawProfileMap, err := readProfiles.ReadProfileAndHash(true, newProfileBytes)
	if (err != nil) { return false, [28]byte{}, err }
	if (ableToRead == false){
		return false, [28]byte{}, errors.New("MyExports contains invalid profile.")	
	}
	if (newProfileNetworkType != networkType){
		return false, [28]byte{}, errors.New("GetMyExportedProfile returning profile with different networkType.")
	}
	if (exportProfileHash != newProfileHash){
		return false, [28]byte{}, errors.New("GetMyExportedProfile returning different profileHash than the profileBytes")
	}
	if (profileIdentityHash != myIdentityHash){
		return false, [28]byte{}, errors.New("New profile identity hash is not mine.")
	}

	checkIfProfileHasChatKeys := func()(bool, error){

		profileIsDisabled, _, err := readProfiles.GetFormattedProfileAttributeFromRawProfileMap(newProfileRawProfileMap, "Disabled")
		if (err != nil) { return false, err }
		if (profileIsDisabled == true){
			return false, nil
		}
		if (myIdentityType == "Mate" || myIdentityType == "Moderator"){
			return true, nil
		}
		return false, nil
	}

	profileHasChatKeys, err := checkIfProfileHasChatKeys()
	if (err != nil) { return false, [28]byte{}, err }
	if (profileHasChatKeys == true){

		// We deal with updating the user's latest chat keys update time
		// We keep track of this locally and send it within all of our chat messages
		// The exported profile's chat keys latest update time will be accurate, based on our existing chat keys

		exists, newProfileChatKeysLatestUpdateTimeString, err := readProfiles.GetFormattedProfileAttributeFromRawProfileMap(newProfileRawProfileMap, "ChatKeysLatestUpdateTime")
		if (err != nil) { return false, [28]byte{}, err }
		if (exists == false){
			return false, [28]byte{}, errors.New("Invalid exported profile: Missing ChatKeysLatestUpdateTime")
		}

		newProfileChatKeysLatestUpdateTime, err := helpers.ConvertStringToInt64(newProfileChatKeysLatestUpdateTimeString)
		if (err != nil) {
			return false, [28]byte{}, errors.New("Invalid exported profile: Contains invalid ChatKeysLatestUpdateTime: " + newProfileChatKeysLatestUpdateTimeString)
		}

		getLatestChatKeysTimeNeedsUpdateBool := func()(bool, error){

			latestUpdateTimeExists, existingChatKeysLatestUpdateTime, err := myChatKeys.GetMyChatKeysLatestUpdateTime(myIdentityHash, networkType)
			if (err != nil) { return false, err }
			if (latestUpdateTimeExists == false){
				// No time exists, we need to update it.
				return true, nil
			}
			if (newProfileChatKeysLatestUpdateTime > existingChatKeysLatestUpdateTime){
				// The profile we are broadcasting has new chat keys.
				return true, nil
			}
			return false, nil
		}

		latestChatKeysTimeNeedsUpdate, err := getLatestChatKeysTimeNeedsUpdateBool()
		if (err != nil) { return false, [28]byte{}, err }
		if (latestChatKeysTimeNeedsUpdate == true){

			err := myChatKeys.SetMyChatKeysLatestUpdateTime(myIdentityHash, networkType, newProfileCreationTime)
			if (err != nil) { return false, [28]byte{}, err }
		}

		exists, newProfileNaclKeyString, err := readProfiles.GetFormattedProfileAttributeFromRawProfileMap(newProfileRawProfileMap, "NaclKey")
		if (err != nil) { return false, [28]byte{}, err }
		if (exists == false) {
			return false, [28]byte{}, errors.New("Invalid export profile: Missing NaclKey")
		}

		exists, newProfileMlkemKeyString, err := readProfiles.GetFormattedProfileAttributeFromRawProfileMap(newProfileRawProfileMap, "MlkemKey")
		if (err != nil) { return false, [28]byte{}, err }
		if (exists == false) {
			return false, [28]byte{}, errors.New("Invalid export profile: Missing MlkemKey")
		}

		exists, newProfileCsidhKeyString, err := readProfiles.GetFormattedProfileAttributeFromRawProfileMap(newProfileRawProfileMap, "CsidhKey")
		if (err != nil) { return false, [28]byte{}, err }
		if (exists == false) {
			return false, [28]byte{}, errors.New("Invalid export profile: Missing CsidhKey")
		}

		newProfileNaclKey, err := nacl.ReadNaclPublicKeyString(newProfileNaclKeyString)
		if (err != nil){
			return false, [28]byte{}, errors.New("Invalid export profile: Contains invalid NaclKey: " + newProfileNaclKeyString)
		}

		newProfileMlkemKey, err := mlkem.ReadMlkemPublicKeyString(newProfileMlkemKeyString)
		if (err != nil){
			return false, [28]byte{}, errors.New("Invalid export profile: Contains invalid MlkemKey: " + newProfileMlkemKeyString)
		}

		newProfileCsidhKey, err := csidh.ReadCsidhPublicKeyString(newProfileCsidhKeyString)
		if (err != nil){
			return false, [28]byte{}, errors.New("Invalid export profile: Contains invalid CsidhKey: " + newProfileCsidhKeyString)
		}

		// These keys may not be different from the existing keys we have saved
		// We dont have to check if they are different, we will set them anyway

		err = myChatKeys.SetMyNewestBroadcastPublicChatKeys(myIdentityHash, networkType, newProfileNaclKey, newProfileMlkemKey, newProfileCsidhKey)
		if (err != nil) { return false, [28]byte{}, err }
	}

	err = DeleteMyBroadcastProfiles(myIdentityHash)
	if (err != nil) { return false, [28]byte{}, err }

	userDirectory, err := localFilesystem.GetAppUserFolderPath()
	if (err != nil) { return false, [28]byte{}, err }

	networkTypeString := helpers.ConvertByteToString(networkType)

	networkTypeFoldername := "Network" + networkTypeString

	profilesFolderPath := goFilepath.Join(userDirectory, "MyBroadcasts", "Profiles", networkTypeFoldername)

	newProfileHashHex := encoding.EncodeBytesToHexString(newProfileHash[:])

	filename := newProfileHashHex + ".messagepack"

	err = localFilesystem.CreateOrOverwriteFile(newProfileBytes, profilesFolderPath, filename)
	if (err != nil) { return false, [28]byte{}, err }

	// We add the profile to our database
	// For moderators, this will help with determining moderation details, such as what is banned/approved
	// For hosts, this will broadcast our profile during our standard host profile seeding tasks
	//
	// TODO: Skip/delay this step for Mate users?
	// For Mate users, this could reveal their identity if the user fulfills their own criteria
	// For example, a user who requests to download profiles after being offline for a while could reveal their identity.
	//		1. User makes a request to download profiles which fulfill their criteria within the host's range
	//		2. Host offers many profiles, some of which have been updated since the user last connected to network
	//		3. User requests to download all profiles which are newer than a given time EXCEPT for their own profile
	//			The user has a newer version of their own profile which the user has recently broadcasted
	//			The host has not received the profile yet via network propagation.

	wellFormed, _, err := profileStorage.AddUserProfile(newProfileBytes)
	if (err != nil) { return false, [28]byte{}, err }
	if (wellFormed == false){
		return false, [28]byte{}, errors.New("Profile to broadcast is not well formed after being well formed already.")
	}

	return true, newProfileHash, nil
}


// This function will delete all broadcast profiles for a provided identity hash
func DeleteMyBroadcastProfiles(myIdentityHash [16]byte)error{

	isValid, err := identity.VerifyIdentityHash(myIdentityHash, false, "")
	if (err != nil) { return err }
	if (isValid == false){
		myIdentityHashHex := encoding.EncodeBytesToHexString(myIdentityHash[:])
		return errors.New("DeleteMyBroadcastProfiles called with invalid identityHash: " + myIdentityHashHex)
	}

	userDirectory, err := localFilesystem.GetAppUserFolderPath()
	if (err != nil) { return err }

	profilesFolderPath := goFilepath.Join(userDirectory, "MyBroadcasts", "Profiles")

	network1ProfilesFolderpath := goFilepath.Join(profilesFolderPath, "Network1")
	network2ProfilesFolderpath := goFilepath.Join(profilesFolderPath, "Network2")

	deleteMyProfilesInFolder := func(folderPath string, networkType byte)error{

		fileList, err := os.ReadDir(folderPath)
		if (err != nil) { return err }

		for _, fileObject := range fileList{

			fileName := fileObject.Name()

			filePath := goFilepath.Join(folderPath, fileName)

			fileBytes, err := os.ReadFile(filePath)
			if (err != nil){ return err }

			ableToRead, _, profileNetworkType, profileAuthor, _, _, _, err := readProfiles.ReadProfile(true, fileBytes)
			if (err != nil) { return err }
			if (ableToRead == false){
				return errors.New("MyBroadcasts malformed: Contains invalid profile.")
			}
			if (profileNetworkType != networkType){
				return errors.New("MyBroadcasts malformed: Contains profile from different networkType.")
			}

			if (profileAuthor != myIdentityHash){
				continue
			}

			err = os.Remove(filePath)
			if (err != nil) { return err }
		}

		return nil
	}

	err = deleteMyProfilesInFolder(network1ProfilesFolderpath, 1)
	if (err != nil) { return err }

	err = deleteMyProfilesInFolder(network2ProfilesFolderpath, 2)
	if (err != nil) { return err }

	return nil
}

func BroadcastMyMessage(messageBytes []byte)error{

	ableToRead, messageHash, _, messageNetworkType, _, _, _, _, _, _, _, err := readMessages.ReadChatMessagePublicDataAndHash(true, messageBytes)
	if (err != nil) { return err }
	if (ableToRead == false){
		return errors.New("BroadcastMyMessage called with invalid message.")
	}

	userDirectory, err := localFilesystem.GetAppUserFolderPath()
	if (err != nil) { return err }

	appNetworkType, err := getAppNetworkType.GetAppNetworkType()
	if (err != nil) { return err }
	if (appNetworkType != messageNetworkType){
		return errors.New("BroadcastMyMessage called with message for different networkType than application.")
	}

	messageNetworkTypeString := helpers.ConvertByteToString(messageNetworkType)

	networkTypeFoldername := "Network" + messageNetworkTypeString

	messagesFolderPath := goFilepath.Join(userDirectory, "MyBroadcasts", "Messages", networkTypeFoldername)

	messageHashHex := encoding.EncodeBytesToHexString(messageHash[:])

	filename := messageHashHex + ".messagepack"

	err = localFilesystem.CreateOrOverwriteFile(messageBytes, messagesFolderPath, filename)
	if (err != nil) { return err }

	return nil	
}

// This function should only be called via the myReviews.CreateAndBroadcastMyReview function
func BroadcastMyReview(newReview []byte)error{

	myIdentityExists, myIdentityHash, err := myIdentity.GetMyIdentityHash("Moderator")
	if (err != nil) { return err }
	if (myIdentityExists == false) {
		return errors.New("Trying to broadcast review when my moderator identity does not exist.")
	}

	ableToRead, newReviewHash, _, newReviewNetworkType, reviewerIdentityHash, _, newReviewType, newReviewedHash, _, _, err := readReviews.ReadReviewAndHash(true, newReview)
	if (err != nil) { return err }
	if (ableToRead == false){
		return errors.New("Trying to broadcast invalid review.")
	}

	if (myIdentityHash != reviewerIdentityHash){
		return errors.New("Trying to broadcast review not created by current moderator identity.")
	}

	userDirectory, err := localFilesystem.GetAppUserFolderPath()
	if (err != nil) { return err }

	newReviewNetworkTypeString := helpers.ConvertByteToString(newReviewNetworkType)

	networkTypeFoldername := "Network" + newReviewNetworkTypeString

	reviewTypeFolderPath := goFilepath.Join(userDirectory, "MyBroadcasts", "Reviews", newReviewType, networkTypeFoldername)

	newReviewHashHex := encoding.EncodeBytesToHexString(newReviewHash[:])

	newReviewFilename := newReviewHashHex + ".messagepack"

	err = localFilesystem.CreateOrOverwriteFile(newReview, reviewTypeFolderPath, newReviewFilename)
	if (err != nil) { return err }

	wellFormed, err := reviewStorage.AddReview(newReview)
	if (err != nil) { return err }
	if (wellFormed == false){
		return errors.New("New review to broadcast is not well formed after being verified already.")
	}

	if (newReviewType == "Profile"){

		if (len(newReviewedHash) != 28){
			reviewedHashHex := encoding.EncodeBytesToHexString(newReviewedHash)
			return errors.New("ReadReview returning invalid length reviewedHash for profile review: " + reviewedHashHex)
		}

		newReviewedProfileHash := [28]byte(newReviewedHash)

		err = mySkippedContent.DeleteProfileFromMySkippedProfilesMap(newReviewedProfileHash)
		if (err != nil) { return err }

	} else if (newReviewType == "Attribute"){

		if (len(newReviewedHash) != 27){
			reviewedHashHex := encoding.EncodeBytesToHexString(newReviewedHash)
			return errors.New("ReadReview returning invalid length reviewedHash for Attribute review: " + reviewedHashHex)
		}

		newReviewedAttributeHash := [27]byte(newReviewedHash)

		err = mySkippedContent.DeleteAttributeFromMySkippedAttributesMap(newReviewedAttributeHash)
		if (err != nil) { return err }

	} else if (newReviewType == "Message"){

		if (len(newReviewedHash) != 26){
			reviewedHashHex := encoding.EncodeBytesToHexString(newReviewedHash)
			return errors.New("ReadReview returning invalid length reviewedHash for Message review: " + reviewedHashHex)
		}

		newReviewedMessageHash := [26]byte(newReviewedHash)

		err = mySkippedContent.DeleteMessageFromMySkippedMessagesMap(newReviewedMessageHash)
		if (err != nil) { return err }
	}

	return nil
}


// This function will prune old reviews that have been replaced by new reviews
// For example, if we approved a message, then banned the same message later, we need to prune the approve review from our broadcasts
func PruneMyBroadcastedReviews()error{

	//TODO
	// If our moderator identity does not exist, delete all of our revies
	// We also need to deal with the reality that full profile approve verdicts replace attribute ban verdicts
	// We also need to deal with the reality that attribute ban verdicts replace full profile approve verdicts
	// We have to delete all reviews that are not the newest.
	// None reviews must be kept, when they are not replaced by other reviews

	return nil
}




