
// myBlockedUsers provides functions to manage a user's blocked users

package myBlockedUsers

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


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

// We will lock this when we are adding users
// This is needed to prevent adding duplicates
var addingBlockedUsersMutex sync.Mutex

var myBlockedUsersMapListDatastore *myMapList.MyMapList

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

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

	myBlockedUsersMapListDatastore = newMyBlockedUsersMapListDatastore

	return nil
}

func BlockUser(identityHash [16]byte, reasonProvided bool, reason string)error{

	addingBlockedUsersMutex.Lock()
	defer addingBlockedUsersMutex.Unlock()

	userIsBlocked, _, _, _, err := CheckIfUserIsBlocked(identityHash)
	if (err != nil) { return err }
	if (userIsBlocked == true){
		// This should not happen, GUI should prevent this
		return errors.New("BlockUser called on user who is already blocked.")
	}

	identityHashString, _, err := identity.EncodeIdentityHashBytesToString(identityHash)
	if (err != nil){
		identityHashHex := encoding.EncodeBytesToHexString(identityHash[:])
		return errors.New("BlockUser called with unvalid identityHash: " + identityHashHex)
	}

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

	newMapItem := map[string]string{
		"IdentityHash": identityHashString,
		"BlockedTime": currentTimeString,
	}

	if (reasonProvided == true){
		newMapItem["Reason"] = reason
	}

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

	return nil
}

func UnblockUser(identityHash [16]byte)error{

	identityHashString, _, err := identity.EncodeIdentityHashBytesToString(identityHash)
	if (err != nil){
		identityHashHex := encoding.EncodeBytesToHexString(identityHash[:])
		return errors.New("UnblockUser called with invalid identityHash: " + identityHashHex)
	}

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

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

	return nil
}

func GetMyBlockedUsersMapList(identityType string)([]map[string]string, error){

	allMyBlockedUsersMapList, err := myBlockedUsersMapListDatastore.GetMapList()
	if (err != nil) { return nil, err }

	myBlockedUsersMapList := make([]map[string]string, 0)

	for _, userMap := range allMyBlockedUsersMapList{

		currentIdentityHashString, exists := userMap["IdentityHash"]
		if (exists == false) {
			return nil, errors.New("MyBlockedUsers map list item missing IdentityHash")
		}

		_, currentIdentityType, err := identity.ReadIdentityHashString(currentIdentityHashString)
		if (err != nil) {
			return nil, errors.New("MyBlockedUsers map list item contains invalid IdentityHash.")
		}
		if (currentIdentityType == identityType) {

			myBlockedUsersMapList = append(myBlockedUsersMapList, userMap)
		}
	}
	
	return myBlockedUsersMapList, nil
}

//Outputs:
//	-bool: User is blocked
//	-int64: Unix time of blocking (if user is blocked)
//	-bool: Reason provided
//	-string: Reason for blocking
//	-error
func CheckIfUserIsBlocked(identityHash [16]byte)(bool, int64, bool, string, error){

	identityHashString, _, err := identity.EncodeIdentityHashBytesToString(identityHash)
	if (err != nil){
		identityHashHex := encoding.EncodeBytesToHexString(identityHash[:])
		return false, 0, false, "", errors.New("CheckIfUserIsBlocked called with invalid identity hash: " + identityHashHex)
	}

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

	anyItemsFound, blockedUsersMapList, err := myBlockedUsersMapListDatastore.GetMapListItems(lookupMap)
	if (err != nil) { return false, 0, false, "", err }
	if (anyItemsFound == false){
		return false, 0, false, "", nil
	}

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

	blockedUserMapItem := blockedUsersMapList[0]

	blockedTimeString, exists := blockedUserMapItem["BlockedTime"]
	if (exists == false) {
		return false, 0, false, "", errors.New("Blocked users map list contains item missing BlockedTime")
	}

	blockedTimeInt64, err := helpers.ConvertStringToInt64(blockedTimeString)
	if (err != nil) {
		return false, 0, false, "", errors.New("My Blocked Users map list contains invalid BlockedTime: " + blockedTimeString)
	}

	reason, exists := blockedUserMapItem["Reason"]
	if (exists == false){
		return true, blockedTimeInt64, false, "", nil
	}

	return true, blockedTimeInt64, true, reason, nil
}


