
// myLikedUsers provides functions to manage a Mate user's liked users
// Users can filter their matches/chat conversations to only show users they have liked
// Users can also view their liked users in the GUI

package myLikedUsers

import "seekia/internal/encoding"
import "seekia/internal/helpers"
import "seekia/internal/identity"
import "seekia/internal/myDatastores/myMapList"

import "sync"
import "errors"
import "time"

// We lock this whenever we are adding a new liked user
// We need this so we don't add duplicates
var addingLikedUserMutex sync.Mutex

var myLikedUsersMapListDatastore *myMapList.MyMapList

// This function must be called whenever an app user signs in
func InitializeMyLikedUsersDatastore()error{

	newMyLikedUsersMapListDatastore, err := myMapList.CreateNewMapList("MyLikedUsers")
	if (err != nil) { return err }

	myLikedUsersMapListDatastore = newMyLikedUsersMapListDatastore

	return nil
}

func LikeUser(userIdentityHash [16]byte)error{

	userIdentityHashString, identityType, err := identity.EncodeIdentityHashBytesToString(userIdentityHash)
	if (err != nil) {
		userIdentityHashHex := encoding.EncodeBytesToHexString(userIdentityHash[:])
		return errors.New("LikeUser called with invalid identity hash: " + userIdentityHashHex)
	}
	if (identityType != "Mate"){
		return errors.New("LikeUser called with non-mate identity hash: " + userIdentityHashString)
	}

	addingLikedUserMutex.Lock()
	defer addingLikedUserMutex.Unlock()

	isLiked, _, err := CheckIfUserIsLiked(userIdentityHash)
	if (err != nil) { return err }
	if (isLiked == true){
		// The GUI should prevent this.
		return errors.New("LikeUser called when user is already liked.")
	}

	currentTimeInt := time.Now().Unix()
	currentTimeString := helpers.ConvertInt64ToString(currentTimeInt)

	newMapItem := map[string]string{
		"IdentityHash": userIdentityHashString,
		"LikedTime": currentTimeString,
	}

	err = myLikedUsersMapListDatastore.AddMapListItem(newMapItem)
	if (err != nil) { return err }

	return nil
}

func UnlikeUser(userIdentityHash [16]byte)error{
	
	userIdentityHashString, identityType, err := identity.EncodeIdentityHashBytesToString(userIdentityHash)
	if (err != nil) {
		userIdentityHashHex := encoding.EncodeBytesToHexString(userIdentityHash[:])
		return errors.New("UnlikeUser called with invalid identity hash: " + userIdentityHashHex)
	}
	if (identityType != "Mate"){
		return errors.New("UnlikeUser called with non-mate identity hash: " + userIdentityHashString)
	}

	mapToDelete := map[string]string{
		"IdentityHash": userIdentityHashString,
	}

	err = myLikedUsersMapListDatastore.DeleteMapListItems(mapToDelete)
	if (err != nil) { return err }

	return nil
}

func GetMyLikedUsersList()([][16]byte, error){

	myLikedUsersMapList, err := myLikedUsersMapListDatastore.GetMapList()
	if (err != nil) { return nil, err }

	likedUsersList := make([][16]byte, 0, len(myLikedUsersMapList))

	for _, userMap := range myLikedUsersMapList{

		userIdentityHashString, exists := userMap["IdentityHash"]
		if (exists == false){
			return nil, errors.New("myLikedUsersMapListDatastore is malformed: Contains item missing IdentityHash")
		}
		userIdentityHash, userIdentityType, err := identity.ReadIdentityHashString(userIdentityHashString)
		if (err != nil){
			return nil, errors.New("myLikedUsersMapListDatastore is malformed: Contains item with invalid IdentityHash: " + userIdentityHashString)
		}
		if (userIdentityType != "Mate"){
			return nil, errors.New("myLikedUsersMapListDatastore is malformed: Contains non-Mate IdentityHash: " + userIdentityType)
		}

		likedUsersList = append(likedUsersList, userIdentityHash)
	}

	return likedUsersList, nil
}

func GetMyLikedUsersMapList()([]map[string]string, error){

	myLikedUsersMapList, err := myLikedUsersMapListDatastore.GetMapList()
	if (err != nil) { return nil, err }

	return myLikedUsersMapList, nil
}

//Outputs:
//	-bool: Is Liked
//	-int64: Unix time of liking (if user is liked)
//	-error
func CheckIfUserIsLiked(userIdentityHash [16]byte)(bool, int64, error){

	userIdentityHashString, identityType, err := identity.EncodeIdentityHashBytesToString(userIdentityHash)
	if (err != nil) {
		userIdentityHashHex := encoding.EncodeBytesToHexString(userIdentityHash[:])
		return false, 0, errors.New("CheckIfUserIsLiked called with invalid identity hash: " + userIdentityHashHex)
	}
	if (identityType != "Mate"){
		return false, 0, errors.New("CheckIfUserIsLiked called with non-mate identity hash.")
	}

	lookupMap := map[string]string{
		"IdentityHash": userIdentityHashString,
	}

	exists, likedUsersMapList, err := myLikedUsersMapListDatastore.GetMapListItems(lookupMap)
	if (err != nil) { return false, 0, err }
	if (exists == false){
		return false, 0, nil
	}

	if (len(likedUsersMapList) != 1){
		return false, 0, errors.New("Liked users map list contains more than 1 entry for an identity hash")
	}

	likedUserMapItem := likedUsersMapList[0]

	likedTimeString, exists := likedUserMapItem["LikedTime"]
	if (exists == false) {
		return false, 0, errors.New("Liked users map list contains item missing LikedTime")
	}

	likedTimeInt64, err := helpers.ConvertStringToInt64(likedTimeString)
	if (err != nil) { return false, 0, err }

	return true, likedTimeInt64, nil
}


