
// myHiddenContent provides functions to manage a moderator's hidden content
// Hidden content is content that the moderator does not want to review
// An example is content written in a language that the moderator does not understand

package myHiddenContent

//TODO: Add job to prune hidden content when we don't need it anymore

import "seekia/internal/encoding"
import "seekia/internal/helpers"
import "seekia/internal/identity"
import "seekia/internal/myDatastores/myMap"
import "seekia/internal/profiles/readProfiles"

import "strings"
import "time"
import "errors"


// Map Structure: Profile Hash -> Added Time + "$" + Author Identity Hash
var myHiddenProfilesMapObject *myMap.MyMap

// Map Structure: Attribute Hash -> Added Time + "$" + Author Identity Hash
var myHiddenAttributesMapObject *myMap.MyMap

// Map Structure: Message Hash -> Added Time + "$" + Author Identity Hash
var myHiddenMessagesMapObject *myMap.MyMap

func InitializeMyHiddenContentDatastores()error{

	newMyHiddenProfilesMapObject, err := myMap.CreateNewMap("MyHiddenProfiles")
	if (err != nil) { return err }

	newMyHiddenAttributesMapObject, err := myMap.CreateNewMap("MyHiddenAttributes")
	if (err != nil) { return err }

	newMyHiddenMessagesMapObject, err := myMap.CreateNewMap("MyHiddenMessages")
	if (err != nil) { return err }

	myHiddenProfilesMapObject = newMyHiddenProfilesMapObject
	myHiddenAttributesMapObject = newMyHiddenAttributesMapObject
	myHiddenMessagesMapObject = newMyHiddenMessagesMapObject

	return nil
}


func AddProfileToMyHiddenProfilesMap(profileHash [28]byte, authorIdentityHash [16]byte)error{

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

	profileHashString := encoding.EncodeBytesToHexString(profileHash[:])

	authorIdentityHashString, _, err := identity.EncodeIdentityHashBytesToString(authorIdentityHash)
	if (err != nil) {
		authorIdentityHashHex := encoding.EncodeBytesToHexString(authorIdentityHash[:])
		return errors.New("AddProfileToMyHiddenProfilesMap called with invalid authorIdentityHash: " + authorIdentityHashHex)
	}

	addedTime := time.Now().Unix()
	addedTimeString := helpers.ConvertInt64ToString(addedTime)

	entryValue := addedTimeString + "$" + authorIdentityHashString

	err = myHiddenProfilesMapObject.SetMapEntry(profileHashString, entryValue)
	if (err != nil) { return err }

	return nil
}


func DeleteProfileFromMyHiddenProfilesMap(profileHash [28]byte)error{

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

	profileHashString := encoding.EncodeBytesToHexString(profileHash[:])

	err = myHiddenProfilesMapObject.DeleteMapEntry(profileHashString)
	if (err != nil) { return err }

	return nil
}

//Outputs:
//	-bool: Profile is hidden
//	-int64: Profile added time
//	-[16]byte: Profile author identity hash
//	-error
func CheckIfProfileIsHidden(profileHash [28]byte)(bool, int64, [16]byte, error){

	isValid, err := readProfiles.VerifyProfileHash(profileHash, false, "", false, false)
	if (err != nil) { return false, 0, [16]byte{}, err }
	if (isValid == false){
		profileHashHex := encoding.EncodeBytesToHexString(profileHash[:])
		return false, 0, [16]byte{}, errors.New("CheckIfProfileIsHidden called with invalid profile hash: " + profileHashHex)
	}

	profileHashHex := encoding.EncodeBytesToHexString(profileHash[:])

	exists, entryValue, err := myHiddenProfilesMapObject.GetMapEntry(profileHashHex)
	if (err != nil) { return false, 0, [16]byte{}, err }
	if (exists == false){
		return false, 0, [16]byte{}, nil
	}

	addedTimeString, authorIdentityHashString, delimiterFound := strings.Cut(entryValue, "$")
	if (delimiterFound == false){
		return false, 0, [16]byte{}, errors.New("myHiddenProfilesMap is malformed: Contains invalid entryValue: " + entryValue)
	}

	addedTimeInt64, err := helpers.ConvertStringToInt64(addedTimeString)
	if (err != nil){
		return false, 0, [16]byte{}, errors.New("myHiddenProfilesMap is malformed: Contains invalid addedTime: " + addedTimeString)
	}

	authorIdentityHash, _, err := identity.ReadIdentityHashString(authorIdentityHashString)
	if (err != nil){
		return false, 0, [16]byte{}, errors.New("myHiddenProfilesMap is malformed: Contains invalid authorIdentityHash: " + authorIdentityHashString)
	}

	return true, addedTimeInt64, authorIdentityHash, nil
}


func GetMyHiddenProfilesMap()(map[[28]byte]int64, error){

	rawHiddenProfilesMap, err := myHiddenProfilesMapObject.GetMap()
	if (err != nil) { return nil, err }

	hiddenProfilesMap := make(map[[28]byte]int64)

	for profileHashString, entryValue := range rawHiddenProfilesMap{

		profileHashBytes, err := encoding.DecodeHexStringToBytes(profileHashString)
		if (err != nil){
			return nil, errors.New("myHiddenProfilesMap is malformed: Contains invalid profileHash: " + profileHashString)
		}

		if (len(profileHashBytes) != 28){
			return nil, errors.New("myHiddenProfilesMap is malformed: Contains invalid length profileHash: " + profileHashString)
		}

		profileHash := [28]byte(profileHashBytes)

		addedTimeString, _, delimiterFound := strings.Cut(entryValue, "$")
		if (delimiterFound == false){
			return nil, errors.New("myHiddenProfilesMap is malformed: Contains invalid entryValue: " + entryValue)
		}

		addedTimeInt64, err := helpers.ConvertStringToInt64(addedTimeString)
		if (err != nil){
			return nil, errors.New("myHiddenProfilesMap is malformed: Contains invalid addedTime: " + addedTimeString)
		}

		hiddenProfilesMap[profileHash] = addedTimeInt64
	}

	return hiddenProfilesMap, nil
}



func AddAttributeToMyHiddenAttributesMap(attributeHash [27]byte, authorIdentityHash [16]byte)error{

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

	attributeHashString := encoding.EncodeBytesToHexString(attributeHash[:])

	authorIdentityHashString, _, err := identity.EncodeIdentityHashBytesToString(authorIdentityHash)
	if (err != nil) {
		authorIdentityHashHex := encoding.EncodeBytesToHexString(authorIdentityHash[:])
		return errors.New("AddAttributeToMyHiddenAttributesMap called with invalid authorIdentityHash: " + authorIdentityHashHex)
	}

	addedTime := time.Now().Unix()
	addedTimeString := helpers.ConvertInt64ToString(addedTime)

	entryValue := addedTimeString + "$" + authorIdentityHashString

	err = myHiddenAttributesMapObject.SetMapEntry(attributeHashString, entryValue)
	if (err != nil) { return err }

	return nil
}


func DeleteAttributeFromMyHiddenAttributesMap(attributeHash [27]byte)error{

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

	attributeHashString := encoding.EncodeBytesToHexString(attributeHash[:])

	err = myHiddenAttributesMapObject.DeleteMapEntry(attributeHashString)
	if (err != nil) { return err }

	return nil
}

//Outputs:
//	-bool: Attribute is hidden
//	-int64: Attribute added time
//	-[16]byte: Attribute author identity hash
//	-error
func CheckIfAttributeIsHidden(attributeHash [27]byte)(bool, int64, [16]byte, error){

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

	attributeHashHex := encoding.EncodeBytesToHexString(attributeHash[:])

	exists, entryValue, err := myHiddenAttributesMapObject.GetMapEntry(attributeHashHex)
	if (err != nil) { return false, 0, [16]byte{}, err }
	if (exists == false){
		return false, 0, [16]byte{}, nil
	}

	addedTimeString, authorIdentityHashString, delimiterFound := strings.Cut(entryValue, "$")
	if (delimiterFound == false){
		return false, 0, [16]byte{}, errors.New("myHiddenAttributesMap is malformed: Contains invalid entryValue: " + entryValue)
	}

	addedTimeInt64, err := helpers.ConvertStringToInt64(addedTimeString)
	if (err != nil){
		return false, 0, [16]byte{}, errors.New("myHiddenAttributesMap is malformed: Contains invalid addedTime: " + addedTimeString)
	}

	authorIdentityHash, _, err := identity.ReadIdentityHashString(authorIdentityHashString)
	if (err != nil){
		return false, 0, [16]byte{}, errors.New("myHiddenAttributesMap is malformed: Contains invalid authorIdentityHash: " + authorIdentityHashString)
	}

	return true, addedTimeInt64, authorIdentityHash, nil
}


func GetMyHiddenAttributesMap()(map[[27]byte]int64, error){

	rawHiddenAttributesMap, err := myHiddenAttributesMapObject.GetMap()
	if (err != nil) { return nil, err }

	hiddenAttributesMap := make(map[[27]byte]int64)

	for attributeHashString, entryValue := range rawHiddenAttributesMap{

		attributeHashBytes, err := encoding.DecodeHexStringToBytes(attributeHashString)
		if (err != nil){
			return nil, errors.New("myHiddenAttributesMap is malformed: Contains invalid attributeHash: " + attributeHashString)
		}

		if (len(attributeHashBytes) != 27){
			return nil, errors.New("myHiddenAttributesMap is malformed: Contains invalid length attributeHash: " + attributeHashString)
		}

		attributeHash := [27]byte(attributeHashBytes)

		addedTimeString, _, delimiterFound := strings.Cut(entryValue, "$")
		if (delimiterFound == false){
			return nil, errors.New("myHiddenAttributesMap is malformed: Contains invalid entryValue: " + entryValue)
		}

		addedTimeInt64, err := helpers.ConvertStringToInt64(addedTimeString)
		if (err != nil){
			return nil, errors.New("myHiddenAttributesMap is malformed: Contains invalid addedTime: " + addedTimeString)
		}

		hiddenAttributesMap[attributeHash] = addedTimeInt64
	}

	return hiddenAttributesMap, nil
}

func AddMessageToMyHiddenMessagesMap(messageHash [26]byte, authorIdentityHash [16]byte)error{

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

	authorIdentityHashString, _, err := identity.EncodeIdentityHashBytesToString(authorIdentityHash)
	if (err != nil) {
		authorIdentityHashHex := encoding.EncodeBytesToHexString(authorIdentityHash[:])
		return errors.New("AddMessageToMyHiddenMessagesMap called with invalid authorIdentityHash: " + authorIdentityHashHex)
	}

	addedTime := time.Now().Unix()
	addedTimeString := helpers.ConvertInt64ToString(addedTime)

	entryValue := addedTimeString + "$" + authorIdentityHashString

	err = myHiddenMessagesMapObject.SetMapEntry(messageHashString, entryValue)
	if (err != nil) { return err }

	return nil
}


func DeleteMessageFromMyHiddenMessagesMap(messageHash [26]byte)error{

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

	err := myHiddenMessagesMapObject.DeleteMapEntry(messageHashString)
	if (err != nil) { return err }

	return nil
}

//Outputs:
//	-bool: Message is hidden
//	-int64: Message added time
//	-[16]byte: Message author identity hash
//	-error
func CheckIfMessageIsHidden(messageHash [26]byte)(bool, int64, [16]byte, error){

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

	exists, entryValue, err := myHiddenMessagesMapObject.GetMapEntry(messageHashHex)
	if (err != nil) { return false, 0, [16]byte{}, err }
	if (exists == false){
		return false, 0, [16]byte{}, nil
	}

	addedTimeString, authorIdentityHashString, delimiterFound := strings.Cut(entryValue, "$")
	if (delimiterFound == false){
		return false, 0, [16]byte{}, errors.New("myHiddenMessagesMap is malformed: Contains invalid entryValue: " + entryValue)
	}

	addedTimeInt64, err := helpers.ConvertStringToInt64(addedTimeString)
	if (err != nil){
		return false, 0, [16]byte{}, errors.New("myHiddenMessagesMap is malformed: Contains invalid addedTime: " + addedTimeString)
	}

	authorIdentityHash, _, err := identity.ReadIdentityHashString(authorIdentityHashString)
	if (err != nil){
		return false, 0, [16]byte{}, errors.New("myHiddenMessagesMap is malformed: Contains invalid authorIdentityHash: " + authorIdentityHashString)
	}

	return true, addedTimeInt64, authorIdentityHash, nil
}


func GetMyHiddenMessagesMap()(map[[26]byte]int64, error){

	rawHiddenMessagesMap, err := myHiddenMessagesMapObject.GetMap()
	if (err != nil) { return nil, err }

	hiddenMessagesMap := make(map[[26]byte]int64)

	for messageHashString, entryValue := range rawHiddenMessagesMap{

		messageHashBytes, err := encoding.DecodeHexStringToBytes(messageHashString)
		if (err != nil){
			return nil, errors.New("myHiddenMessagesMap is malformed: Contains invalid messageHash: " + messageHashString)
		}

		if (len(messageHashBytes) != 26){
			return nil, errors.New("myHiddenMessagesMap is malformed: Contains invalid length messageHash: " + messageHashString)
		}

		messageHash := [26]byte(messageHashBytes)

		addedTimeString, _, delimiterFound := strings.Cut(entryValue, "$")
		if (delimiterFound == false){
			return nil, errors.New("myHiddenMessagesMap is malformed: Contains invalid entryValue: " + entryValue)
		}

		addedTimeInt64, err := helpers.ConvertStringToInt64(addedTimeString)
		if (err != nil){
			return nil, errors.New("myHiddenMessagesMap is malformed: Contains invalid addedTime: " + addedTimeString)
		}

		hiddenMessagesMap[messageHash] = addedTimeInt64
	}

	return hiddenMessagesMap, nil
}


