
// myReviews provides functions to retrieve a user's moderator reviews
// This package retrieves our reviews from the database.
// myBroadcasts keeps a backup of a moderator's reviews that is retained if the database is deleted.

package myReviews

import "seekia/internal/badgerDatabase"
import "seekia/internal/contentMetadata"
import "seekia/internal/encoding"
import "seekia/internal/helpers"
import "seekia/internal/identity"
import "seekia/internal/moderation/createReviews"
import "seekia/internal/moderation/readReviews"
import "seekia/internal/myIdentity"
import "seekia/internal/network/myBroadcasts"
import "seekia/internal/profiles/profileStorage"
import "seekia/internal/profiles/readProfiles"

import "slices"
import "bytes"
import "sync"
import "errors"


// This function will create and broadcast a new moderator review
//Outputs:
//	-bool: My moderator identity exists
//	-error
func CreateAndBroadcastMyReview(reviewMap map[string]string)(bool, error){

	exists, myIdentityPublicKey, myIdentityPrivateKey, err := myIdentity.GetMyPublicPrivateIdentityKeys("Moderator")
	if (err != nil) { return false, err }
	if (exists == false){
		return false, nil
	}

	newReview, err := createReviews.CreateReview(myIdentityPublicKey, myIdentityPrivateKey, reviewMap)
	if (err != nil) { return false, err }

	err = myBroadcasts.BroadcastMyReview(newReview)
	if (err != nil) { return false, err }

	ableToRead, _, _, _, _, newReviewType, _, _, _, err := readReviews.ReadReview(false, newReview)
	if (err != nil) { return false, err }
	if (ableToRead == false){
		return false, errors.New("CreateReview is returning an invalid review.")
	}

	err = DeleteMyReviewsListCache(newReviewType)
	if (err != nil) { return false, err }

	return true, nil
}

// This function will return what a user's current verdict is for an identity
//Outputs:
//	-bool: My Moderator Identity exists
//	-bool: I have banned the identity
//	-error
func GetMyNewestIdentityModerationVerdict(identityHash [16]byte, networkType byte)(bool, bool, error){

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

	myIdentityExists, myIdentityHash, err := myIdentity.GetMyIdentityHash("Moderator")
	if (err != nil) { return false, false, err }
	if (myIdentityExists == false){
		return false, false, nil
	}

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

	myReviewsList, err := getMyReviewsList(myIdentityHash, "Identity")
	if (err != nil) { return false, false, err }

	if (len(myReviewsList) == 0){
		// Moderator has no reviews yet
		return true, false, nil
	}

	reviewExists, _, _, err := readReviews.GetModeratorNewestIdentityReviewFromReviewsList(myReviewsList, myIdentityHash, identityHash, networkType)
	if (err != nil){ return false, false, err }
	if (reviewExists == true){
		// Review must be a ban review, because Identities can only be banned
		return true, true, nil
	}

	return true, false, nil
}


// This function will return what a user's current verdict is for a profile
// This will optionally check for profile attribute bans which would undo a full profile approval
// It will not check if we have banned the author identity
//Outputs:
//	-bool: My Moderator identity exists
//	-bool: Profile is disabled
//	-bool: Profile metadata exists (needed to determine verdict)
//	-bool: I have reviewed the profile (review exists and is not None)
//	-string: Verdict ("Ban"/"Approve")
//	-error
func GetMyNewestProfileModerationVerdict(profileHash [28]byte, integrateAttributeBans bool)(bool, bool, bool, bool, string, error){

	myIdentityExists, myIdentityHash, err := myIdentity.GetMyIdentityHash("Moderator")
	if (err != nil) { return false, false, false, false, "", err }
	if (myIdentityExists == false){
		return false, false, false, false, "", nil
	}

	_, profileIsDisabled, err := readProfiles.ReadProfileHashMetadata(profileHash)
	if (err != nil){
		profileHashHex := encoding.EncodeBytesToHexString(profileHash[:])
		return false, false, false, false, "", errors.New("GetMyNewestProfileModerationVerdict called with invalid profile hash: " + profileHashHex)
	}

	metadataExists, _, profileNetworkType, _, _, profileIsDisabledB, _, attributeHashesMap, err := contentMetadata.GetProfileMetadata(profileHash)
	if (err != nil) { return false, false, false, false, "", err }
	if (metadataExists == false){
		return true, profileIsDisabled, false, false, "", nil
	}
	if (profileIsDisabled != profileIsDisabledB){
		return false, false, false, false, "", errors.New("GetProfileMetadata returning different profileIsDisabled status than ReadProfileHashMetadata.")
	}
	if (profileIsDisabled == true){
		// Profile is disabled. It cannot be reviewed.
		return true, true, true, false, "", nil
	}

	myProfileReviewsList, err := getMyReviewsList(myIdentityHash, "Profile")
	if (err != nil) { return false, false, false, false, "", err }

	fullProfileReviewExists, _, _, fullProfileVerdict, fullProfileVerdictTime, err := readReviews.GetModeratorNewestProfileReviewFromReviewsList(myProfileReviewsList, myIdentityHash, profileHash, profileNetworkType)
	if (err != nil){ return false, false, false, false, "", err }

	if (integrateAttributeBans == false){
		if (fullProfileReviewExists == true){

			return true, false, true, true, fullProfileVerdict, nil
		}

		return true, false, true, false, "", nil
	}

	if (fullProfileReviewExists == true && fullProfileVerdict == "Ban"){
		// We do not have to check if we have banned any profile attributes, because we have already banned the full profile
		return true, false, true, true, "Ban", nil
	}

	// Now we see if we have banned any attributes belonging to this profile

	for _, attributeHash := range attributeHashesMap{

		myIdentityExists, attributeMetadataExists, reviewExists, myVerdict, myVerdictTime, err := GetMyNewestProfileAttributeModerationVerdict(attributeHash, false)
		if (err != nil) { return false, false, false, false, "", err }
		if (myIdentityExists == false){
			return false, false, false, false, "", errors.New("My identity not found after being found already.")
		}
		if (attributeMetadataExists == false){
			// We don't have knowledge of profiles belonging to this profile in the attributeProfileHashesList entry in the database
			// This should not happen unless those entries were deleted
			// We will interpret this the same as no other profiles existing which contain this attribute
			continue
		}
		if (reviewExists == true && myVerdict == "Ban"){

			if (fullProfileReviewExists == true && myVerdictTime < fullProfileVerdictTime){
				// We have approved the full profile after we banned this attribute
				continue
			}
			// We have banned a profile attribute, thus, we have banned the profile.

			return true, false, true, true, "Ban", nil
		}
	}

	if (fullProfileReviewExists == true){
		// We could not find any attribute bans that undo the full profile approval
		return true, false, true, true, "Approve", nil
	}

	return true, false, true, false, "", nil
}


// This function will return a user's newest profile attribute verdict
// It will optionally check for full profile approvals, which it considers the same as approving all of the profile's attributes
//Outputs:
//	-bool: My Moderator identity exists
//	-bool: Attribute metadata exists (this is needed to determine verdict)
//	-bool: I have reviewed the attribute (review exists and is not None)
//	-string: Verdict ("Ban"/"Approve")
//	-int64: Time of verdict
//	-error
func GetMyNewestProfileAttributeModerationVerdict(attributeHash [27]byte, integrateFullProfileApprovals bool)(bool, bool, bool, string, int64, error){

	myIdentityExists, myIdentityHash, err := myIdentity.GetMyIdentityHash("Moderator")
	if (err != nil) { return false, false, false, "", 0, err }
	if (myIdentityExists == false){
		return false, false, false, "", 0, nil
	}

	isValid, err := readProfiles.VerifyAttributeHash(attributeHash, false, "", false, false)
	if (err != nil) { return false, false, false, "", 0, err }
	if (isValid == false){
		attributeHashHex := encoding.EncodeBytesToHexString(attributeHash[:])
		return false, false, false, "", 0, errors.New("GetMyNewestProfileAttributeModerationVerdict called with invalid attributeHash: " + attributeHashHex)
	}

	attributeMetadataExists, _, _, attributeNetworkType, attributeProfileHashesList, err := profileStorage.GetProfileAttributeMetadata(attributeHash)
	if (err != nil) { return false, false, false, "", 0, err }
	if (attributeMetadataExists == false){
		// We cannot determine verdict.
		return true, false, false, "", 0, nil
	}

	myAttributeReviewsList, err := getMyReviewsList(myIdentityHash, "Attribute")
	if (err != nil) { return false, false, false, "", 0, err }

	attributeReviewExists, _, _, attributeReviewVerdict, attributeReviewTime, err := readReviews.GetModeratorNewestProfileAttributeReviewFromReviewsList(myAttributeReviewsList, myIdentityHash, attributeHash, attributeNetworkType)
	if (err != nil){ return false, false, false, "", 0, err }

	if (integrateFullProfileApprovals == false){

		if (attributeReviewExists == false){
			return true, true, false, "", 0, nil
		}

		return true, true, true, attributeReviewVerdict, attributeReviewTime, nil
	}

	if (attributeReviewExists == true && attributeReviewVerdict == "Approve"){

		// We approved the attribute
		// We don't have to check for full profile approvals, because they would not change this verdict

		return true, true, true, "Approve", attributeReviewTime, nil
	}

	// Now we check for full profile approvals
	// A full profile approval is equivalent to an attribute approval for all attributes within the profile
	// attributeProfileHashesList is a list of all profile hashes for profiles which contain the attribute

	myProfileReviewsList, err := getMyReviewsList(myIdentityHash, "Profile")
	if (err != nil) { return false, false, false, "", 0, err }

	for _, profileHash := range attributeProfileHashesList{

		// We are only checking for full profile approvals
		// We don't need to check for profile attribute bans, because we are only concerned with the provided attribute's status
		// A full profile approval approves all attributes.
		// If we ban a full profile, it does not change the status of any of our attribute approvals of the profile

		fullProfileReviewExists, _, _, fullProfileVerdict, fullProfileVerdictTime, err := readReviews.GetModeratorNewestProfileReviewFromReviewsList(myProfileReviewsList, myIdentityHash, profileHash, attributeNetworkType)
		if (err != nil){ return false, false, false, "", 0, err }
		if (fullProfileReviewExists == true && fullProfileVerdict == "Approve"){

			if (attributeReviewExists == true && fullProfileVerdictTime < attributeReviewTime){
				// We banned the attribute after approving the full profile
				// The attribute ban is therefore disregarded.
				continue
			}
			// We have approved the full profile after banning the attribute, thus, the attribute is approved

			return true, true, true, "Approve", fullProfileVerdictTime, nil
		}
	}

	if (attributeReviewExists == true){
		// We could not find any full profile approvals that undo the attribute ban
		return true, true, true, "Ban", attributeReviewTime, nil
	}

	return true, true, false, "", 0, nil
}


// This function will return what a user's current verdict is for a message
//	-bool: My Moderator Identity exists
//	-bool: Message metadata exists (this is needed to determine our verdict)
//	-bool: I have reviewed the message (review exists and is not None)
//	-string: Verdict ("Ban"/"Approve")
//	-error
func GetMyNewestMessageModerationVerdict(messageHash [26]byte)(bool, bool, bool, string, error){

	myIdentityExists, myIdentityHash, err := myIdentity.GetMyIdentityHash("Moderator")
	if (err != nil) { return false, false, false, "", err }
	if (myIdentityExists == false){
		return false, false, false, "", nil
	}

	messageMetadataExists, _, messageNetworkType, _, _, messageCipherKeyHash, err := contentMetadata.GetMessageMetadata(messageHash)
	if (err != nil){ return false, false, false, "", err }
	if (messageMetadataExists == false){
		// We cannot determine our verdict without message metadata
		return true, false, false, "", nil
	}

	myReviewsList, err := getMyReviewsList(myIdentityHash, "Message")
	if (err != nil) { return false, false, false, "", err }

	if (len(myReviewsList) == 0){
		// Moderator has no reviews yet
		return true, true, false, "", nil
	}

	reviewExists, _, _, reviewVerdict, err := readReviews.GetModeratorNewestMessageReviewFromReviewsList(myReviewsList, myIdentityHash, messageHash, messageNetworkType, messageCipherKeyHash)
	if (err != nil){ return false, false, false, "", err }
	if (reviewExists == false){
		return true, true, false, "", nil
	}

	return true, true, true, reviewVerdict, nil
}

// This function returns a list of all the identity hashes that the user has banned
//Outputs:
//	-bool: My Moderator identity exists
//	-[][16]byte: List of identity hashes user has banned
//	-error
func GetMyBannedIdentityHashesList(networkType byte)(bool, [][16]byte, error){

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

	myIdentityExists, myIdentityHash, err := myIdentity.GetMyIdentityHash("Moderator")
	if (err != nil) { return false, nil, err }
	if (myIdentityExists == false){
		return false, nil, nil
	}

	myIdentityReviewsMap, err := getMyNewestReviewsMap(myIdentityHash, "Identity", networkType)
	if (err != nil) { return false, nil, err }

	bannedIdentityHashesList := make([][16]byte, 0, len(myIdentityReviewsMap))

	for reviewedIdentityHashString, _ := range myIdentityReviewsMap{

		reviewedIdentityHashBytes := []byte(reviewedIdentityHashString)

		if (len(reviewedIdentityHashBytes) != 16){
			reviewedIdentityHashHex := encoding.EncodeBytesToHexString(reviewedIdentityHashBytes)
			return false, nil, errors.New("getMyNewestReviewsMap returning invalid reviewedIdentityHash: " + reviewedIdentityHashHex)
		}

		reviewedIdentityHash := [16]byte(reviewedIdentityHashBytes)

		bannedIdentityHashesList = append(bannedIdentityHashesList, reviewedIdentityHash)
	}

	return true, bannedIdentityHashesList, nil
}


//Outputs:
//	-bool: My Moderator identity exists
//	-map[[28]byte]string: Map of profile hashes user has reviewed (Profile hash -> "Approve"/"Ban")
//	-error
func GetMyReviewedProfileHashesMap(profileType string, networkType byte)(bool, map[[28]byte]string, error){

	if (profileType != "Mate" && profileType != "Host" && profileType != "Moderator"){
		return false, nil, errors.New("GetMyReviewedProfileHashesMap called with invalid profile type: " + profileType)
	}

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

	myIdentityExists, _, err := myIdentity.GetMyIdentityHash("Moderator")
	if (err != nil) { return false, nil, err }
	if (myIdentityExists == false){
		return false, nil, nil
	}

	allProfileHashesList, err := badgerDatabase.GetAllProfileHashes(profileType)
	if (err != nil) { return false, nil, err }

	//Map structure: Profile hash -> My Verdict
	myReviewedProfileHashesMap := make(map[[28]byte]string)

	for _, profileHash := range allProfileHashesList{

		myIdentityExists, profileIsDisabled, profileMetadataExists, iHaveReviewed, myVerdict, err := GetMyNewestProfileModerationVerdict(profileHash, true)
		if (err != nil) { return false, nil, err }
		if (myIdentityExists == false){
			return false, nil, errors.New("My identity not found after being found already.")
		}
		if (profileIsDisabled == true){
			continue
		}
		if (profileMetadataExists == false){
			continue
		}

		if (iHaveReviewed == true){
			myReviewedProfileHashesMap[profileHash] = myVerdict
		}
	}

	return true, myReviewedProfileHashesMap, nil
}

//Outputs:
//	-bool: My Moderator identity exists
//	-map[[27]byte]string: Map Structure: Attribute Hash -> Verdict
//		-Map of profile attribute hashes user has reviewed (approved or banned)
//	-error
func GetMyReviewedProfileAttributeHashesMap(networkType byte)(bool, map[[27]byte]string, error){

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

	myIdentityExists, _, err := myIdentity.GetMyIdentityHash("Moderator")
	if (err != nil) { return false, nil, err }
	if (myIdentityExists == false){
		return false, nil, nil
	}

	allProfileAttributeHashesList, err := badgerDatabase.GetAllReviewedProfileAttributeHashes()
	if (err != nil) { return false, nil, err }

	//Map structure: Attribute hash -> My verdict
	myAttributeVerdictsMap := make(map[[27]byte]string)

	for _, attributeHash := range allProfileAttributeHashesList{

		myIdentityExists, attributeMetadataExists, myReviewExists, myVerdict, _, err := GetMyNewestProfileAttributeModerationVerdict(attributeHash, true)
		if (err != nil) { return false, nil, err }
		if (myIdentityExists == false){
			return false, nil, errors.New("My moderator identity not found after being found already.")
		}
		if (attributeMetadataExists == false){
			// We cannot determine our verdict for this attribute
			continue
		}
		if (myReviewExists == true){
			myAttributeVerdictsMap[attributeHash] = myVerdict
		}
	}

	return true, myAttributeVerdictsMap, nil
}


//Outputs:
//	-bool: My Moderator identity exists
//	-[][26]byte: List of message hashes user has reviewed (approved or banned)
//	-error
func GetMyReviewedMessageHashesList(networkType byte)(bool, [][26]byte, error){

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

	myIdentityExists, myIdentityHash, err := myIdentity.GetMyIdentityHash("Moderator")
	if (err != nil) { return false, nil, err }
	if (myIdentityExists == false){
		return false, nil, nil
	}

	myMessageReviewsMap, err := getMyNewestReviewsMap(myIdentityHash, "Message", networkType)
	if (err != nil) { return false, nil, err }

	myReviewedMessageHashesList := make([][26]byte, 0, len(myMessageReviewsMap))

	for messageHashString, reviewBytes := range myMessageReviewsMap{

		messageHashBytes := []byte(messageHashString)

		if (len(messageHashBytes) != 26){
			messageHashHex := encoding.EncodeBytesToHexString(messageHashBytes)
			return false, nil, errors.New("getMyNewestReviewsMap returning reviewsMap with invalid messageHash map key: " + messageHashHex)
		}

		messageHashArray := [26]byte(messageHashBytes)

		ableToRead, _, reviewNetworkType, reviewerIdentityHash, _, reviewType, reviewedHash, _, _, err := readReviews.ReadReview(false, reviewBytes)
		if (err != nil) { return false, nil, err }
		if (ableToRead == false){
			return false, nil, errors.New("getMyNewestReviewsMap returning invalid review.")
		}
		if (reviewNetworkType != networkType){
			return false, nil, errors.New("getMyNewestReviewsMap returning review of different networkType.")
		}

		if (reviewerIdentityHash != myIdentityHash){
			return false, nil, errors.New("getMyNewestReviewsMap list contains review by different reviewer")
		}

		if (reviewType != "Message"){
			return false, nil, errors.New("getMyNewestReviewsMap returns different reviewType review: " + reviewType)
		}

		areEqual := bytes.Equal(reviewedHash, messageHashBytes)
		if (areEqual == false){
			return false, nil, errors.New("getMyNewestReviewsMap returns key with different review reviewedHash")
		}

		myReviewedMessageHashesList = append(myReviewedMessageHashesList, messageHashArray)
	}

	return true, myReviewedMessageHashesList, nil
}


//Outputs:
//	-bool: User moderator identity found
//	-[][]byte: List of all reviews created by user, sorted from newest to oldest (Reviews with None verdict not included)
//	-error
func GetMyNewestReviewsListSorted(reviewType string, networkType byte)(bool, [][]byte, error){

	if (reviewType != "Identity" && reviewType != "Profile" && reviewType != "Attribute" && reviewType != "Message"){
		return false, nil, errors.New("GetMyNewestReviewsListSorted called with invalid reviewType: " + reviewType)
	}

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

	myIdentityExists, myIdentityHash, err := myIdentity.GetMyIdentityHash("Moderator")
	if (err != nil) { return false, nil, err }
	if (myIdentityExists == false){
		return false, nil, nil
	}

	myNewestReviewsMap, err := getMyNewestReviewsMap(myIdentityHash, reviewType, networkType)
	if (err != nil) { return false, nil, err }

	type ReviewObject struct{
		ReviewCreationTime int64
		ReviewBytes []byte
	}

	newestReviewObjectsList := make([]ReviewObject, 0, len(myNewestReviewsMap))

	for reviewedHashString, reviewBytes := range myNewestReviewsMap{

		reviewedHashBytes := []byte(reviewedHashString)

		ableToRead, _, reviewNetworkType, reviewAuthorIdentityHash, reviewCreationTime, currentReviewType, currentReviewedHash, _, _, err := readReviews.ReadReview(false, reviewBytes)
		if (err != nil) { return false, nil, err }
		if (ableToRead == false){
			return false, nil, errors.New("getMyNewestReviewsMap returning invalid review")
		}
		if (reviewNetworkType != networkType){
			return false, nil, errors.New("getMyNewestReviewsMap returning review for different networkType.")
		}
		if (reviewAuthorIdentityHash != myIdentityHash){
			return false, nil, errors.New("getMyNewestReviewsMap returning review by different author.")
		}
		if (currentReviewType != reviewType){
			return false, nil, errors.New("getMyNewestReviewsMap returning review of a different reviewType.")
		}
		areEqual := bytes.Equal(reviewedHashBytes, currentReviewedHash)
		if (areEqual == false){
			return false, nil, errors.New("getMyNewestReviewsMap returning map where reviewedHash key does not match reviewBytes's.")		
		}

		reviewObject := ReviewObject{
			ReviewCreationTime: reviewCreationTime,
			ReviewBytes: reviewBytes,
		}

		newestReviewObjectsList = append(newestReviewObjectsList, reviewObject)
	}

	compareReviewsFunction := func(review1 ReviewObject, review2 ReviewObject)int{

		review1CreationTime := review1.ReviewCreationTime
		review2CreationTime := review2.ReviewCreationTime

		if (review1CreationTime == review2CreationTime){
			return 0
		}

		if (review1CreationTime < review2CreationTime){
			return 1
		}

		return -1
	}

	slices.SortFunc(newestReviewObjectsList, compareReviewsFunction)

	newestReviewsList := make([][]byte, 0, len(newestReviewObjectsList))

	for _, reviewObject := range newestReviewObjectsList{

		reviewBytes := reviewObject.ReviewBytes

		newestReviewsList = append(newestReviewsList, reviewBytes)
	}

	return true, newestReviewsList, nil
}

//Outputs:
//	-map[string]string: Reviewed Hash -> Newest Review Bytes
//	-error
func getMyNewestReviewsMap(myIdentityHash [16]byte, reviewType string, networkType byte)(map[string][]byte, error){

	if (reviewType != "Identity" && reviewType != "Profile" && reviewType != "Attribute" && reviewType != "Message"){
		return nil, errors.New("getMyNewestReviewsMap called with invalid reviewType: " + reviewType)
	}

	reviewsList, err := getMyReviewsList(myIdentityHash, reviewType)
	if (err != nil) { return nil, err }

	newestReviewsMap, err := readReviews.GetNewestModeratorReviewsMapFromReviewsList(reviewsList, myIdentityHash, networkType, true, reviewType)
	if (err != nil) { return nil, err }

	return newestReviewsMap, nil
}


// We read our reviews into memory so we don't have to retrieve them from the database each time

var myIdentityReviewsList []readReviews.ReviewWithHash
var myIdentityReviewsListMutex sync.RWMutex

var myProfileReviewsList []readReviews.ReviewWithHash
var myProfileReviewsListMutex sync.RWMutex

var myAttributeReviewsList []readReviews.ReviewWithHash
var myAttributeReviewsListMutex sync.RWMutex

var myMessageReviewsList []readReviews.ReviewWithHash
var myMessageReviewsListMutex sync.RWMutex

// We call this function whenever we add a new review to the database
func DeleteMyReviewsListCache(reviewType string)error{

	if (reviewType == "Identity"){

		myIdentityReviewsListMutex.Lock()
		myIdentityReviewsList = nil
		myIdentityReviewsListMutex.Unlock()

		return nil

	} else if (reviewType == "Profile"){

		myProfileReviewsListMutex.Lock()
		myProfileReviewsList = nil
		myProfileReviewsListMutex.Unlock()

		return nil

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

		myAttributeReviewsListMutex.Lock()
		myAttributeReviewsList = nil
		myAttributeReviewsListMutex.Unlock()

		return nil

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

		myMessageReviewsListMutex.Lock()
		myMessageReviewsList = nil
		myMessageReviewsListMutex.Unlock()

		return nil
	}

	return errors.New("DeleteMyReviewsListCache called with invalid reviewType: " + reviewType)
}


// This function returns our reviews for all networkTypes.
// It does not copy each review object's review bytes, so returned review bytes should never be edited
func getMyReviewsList(myIdentityHash [16]byte, reviewType string)([]readReviews.ReviewWithHash, error){

	// We first attempt to return the list stored in memory

	if (reviewType == "Identity"){

		myIdentityReviewsListMutex.RLock()
		if (myIdentityReviewsList != nil){

			listCopy := slices.Clone(myIdentityReviewsList)
			myIdentityReviewsListMutex.RUnlock()

			return listCopy, nil
		}
		myIdentityReviewsListMutex.RUnlock()

	} else if (reviewType == "Profile"){

		myProfileReviewsListMutex.RLock()
		if (myProfileReviewsList != nil){

			listCopy := slices.Clone(myProfileReviewsList)
			myProfileReviewsListMutex.RUnlock()

			return listCopy, nil
		}
		myProfileReviewsListMutex.RUnlock()

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

		myAttributeReviewsListMutex.RLock()
		if (myAttributeReviewsList != nil){

			listCopy := slices.Clone(myAttributeReviewsList)
			myAttributeReviewsListMutex.RUnlock()

			return listCopy, nil
		}
		myAttributeReviewsListMutex.RUnlock()

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

		myMessageReviewsListMutex.RLock()
		if (myMessageReviewsList != nil){

			listCopy := slices.Clone(myMessageReviewsList)
			myMessageReviewsListMutex.RUnlock()

			return listCopy, nil
		}
		myMessageReviewsListMutex.RUnlock()
	} else {
		return nil, errors.New("getMyReviewsList called with invalid reviewType: " + reviewType)
	}

	// The list does not exist in memory
	// We will create a new list

	exists, myReviewHashesList, err := badgerDatabase.GetReviewerReviewHashesList(myIdentityHash, reviewType)
	if (err != nil) { return nil, err }
	if (exists == false){
		emptyList := make([]readReviews.ReviewWithHash, 0)
		return emptyList, nil
	}

	newReviewsList := make([]readReviews.ReviewWithHash, 0)

	for _, reviewHash := range myReviewHashesList{

		exists, reviewBytes, err := badgerDatabase.GetReview(reviewHash)
		if (err != nil) { return nil, err }
		if (exists == false) {
			// Reviewer reviews list is outdated, will be updated automatically
			continue		
		}

		reviewObject := readReviews.ReviewWithHash{
			ReviewHash: reviewHash,
			ReviewBytes: reviewBytes,
		}

		newReviewsList = append(newReviewsList, reviewObject)
	}

	if (reviewType == "Identity"){

		myIdentityReviewsListMutex.Lock()

		myIdentityReviewsList = newReviewsList

		listCopy := slices.Clone(myIdentityReviewsList)

		myIdentityReviewsListMutex.Unlock()
		
		return listCopy, nil

	} else if (reviewType == "Profile"){

		myProfileReviewsListMutex.Lock()

		myProfileReviewsList = newReviewsList

		listCopy := slices.Clone(myProfileReviewsList)

		myProfileReviewsListMutex.Unlock()

		return listCopy, nil

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

		myAttributeReviewsListMutex.Lock()

		myAttributeReviewsList = newReviewsList

		listCopy := slices.Clone(myAttributeReviewsList)

		myAttributeReviewsListMutex.Unlock()

		return listCopy, nil
	}
	// reviewType == "Message"){

	myMessageReviewsListMutex.Lock()

	myMessageReviewsList = newReviewsList

	listCopy := slices.Clone(myMessageReviewsList)

	myMessageReviewsListMutex.Unlock()

	return listCopy, nil
}




