
// mySkippedContent provides functions to manage a moderator's skipped content
// Skipped content is content that the moderator has skipped while reviewing content
// Skipped content will be moved to the end of the myUnreviewed queue

package mySkippedContent

//TODO: Add job to prune skipped 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 "errors"
import "strings"
import "time"

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

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

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

func InitializeMySkippedContentDatastores()error{

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

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

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

	mySkippedProfilesMapObject = newMySkippedProfilesMapObject
	mySkippedAttributesMapObject = newMySkippedAttributesMapObject
	mySkippedMessagesMapObject = newMySkippedMessagesMapObject

	return nil
}


func AddProfileToMySkippedProfilesMap(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("AddProfileToMySkippedProfilesMap 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("AddProfileToMySkippedProfilesMap called with invalid authorIdentityHash: " + authorIdentityHashHex)
	}

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

	entryValue := addedTimeString + "$" + authorIdentityHashString

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

	return nil
}


func DeleteProfileFromMySkippedProfilesMap(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("DeleteProfileFromMySkippedProfilesMap called with invalid profile hash: " + profileHashHex)
	}

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

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

	return nil
}

//Outputs:
//	-bool: Profile is skipped
//	-int64: Profile added time
//	-[16]byte: Profile author identity hash
//	-error
func CheckIfProfileIsSkipped(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("CheckIfProfileIsSkipped called with invalid profile hash: " + profileHashHex)
	}

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

	exists, entryValue, err := mySkippedProfilesMapObject.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("mySkippedProfilesMap is malformed: Contains invalid entryValue: " + entryValue)
	}

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

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

	return true, addedTimeInt64, authorIdentityHash, nil
}


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

	rawSkippedProfilesMap, err := mySkippedProfilesMapObject.GetMap()
	if (err != nil) { return nil, err }

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

	for profileHashString, entryValue := range rawSkippedProfilesMap{

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

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

		profileHash := [28]byte(profileHashBytes)

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

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

		skippedProfilesMap[profileHash] = addedTimeInt64
	}

	return skippedProfilesMap, nil
}



func AddAttributeToMySkippedAttributesMap(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("AddAttributeToMySkippedAttributesMap 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("AddAttributeToMySkippedAttributesMap called with invalid authorIdentityHash: " + authorIdentityHashHex)
	}

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

	entryValue := addedTimeString + "$" + authorIdentityHashString

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

	return nil
}


func DeleteAttributeFromMySkippedAttributesMap(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("DeleteAttributeFromMySkippedAttributesMap called with invalid attribute hash: " + attributeHashHex)
	}

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

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

	return nil
}

//Outputs:
//	-bool: Attribute is skipped
//	-int64: Attribute added time
//	-[16]byte: Attribute author identity hash
//	-error
func CheckIfAttributeIsSkipped(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("CheckIfAttributeIsSkipped called with invalid attribute hash: " + attributeHashHex)
	}

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

	exists, entryValue, err := mySkippedAttributesMapObject.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("mySkippedAttributesMap is malformed: Contains invalid entryValue: " + entryValue)
	}

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

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

	return true, addedTimeInt64, authorIdentityHash, nil
}


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

	rawSkippedAttributesMap, err := mySkippedAttributesMapObject.GetMap()
	if (err != nil) { return nil, err }

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

	for attributeHashString, entryValue := range rawSkippedAttributesMap{

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

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

		attributeHash := [27]byte(attributeHashBytes)

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

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

		skippedAttributesMap[attributeHash] = addedTimeInt64
	}

	return skippedAttributesMap, nil
}

func AddMessageToMySkippedMessagesMap(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("AddMessageToMySkippedMessagesMap called with invalid authorIdentityHash: " + authorIdentityHashHex)
	}

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

	entryValue := addedTimeString + "$" + authorIdentityHashString

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

	return nil
}


func DeleteMessageFromMySkippedMessagesMap(messageHash [26]byte)error{

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

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

	return nil
}

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

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

	exists, entryValue, err := mySkippedMessagesMapObject.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("mySkippedMessagesMap is malformed: Contains invalid entryValue: " + entryValue)
	}

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

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

	return true, addedTimeInt64, authorIdentityHash, nil
}


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

	rawSkippedMessagesMap, err := mySkippedMessagesMapObject.GetMap()
	if (err != nil) { return nil, err }

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

	for messageHashString, entryValue := range rawSkippedMessagesMap{

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

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

		messageHash := [26]byte(messageHashBytes)

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

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

		skippedMessagesMap[messageHash] = addedTimeInt64
	}

	return skippedMessagesMap, nil
}




