
// myChatFilters provides functions to determine if a peer passes a user's chat filters.
// It also provides functions to edit a user's chat filters.

package myChatFilters

import "seekia/internal/desires/myMateDesires"
import "seekia/internal/encoding"
import "seekia/internal/helpers"
import "seekia/internal/identity"
import "seekia/internal/messaging/myChatMessages"
import "seekia/internal/myContacts"
import "seekia/internal/myDatastores/myMap"
import "seekia/internal/myIgnoredUsers"
import "seekia/internal/myLikedUsers"
import "seekia/internal/mySettings"
import "seekia/internal/profiles/viewableProfiles"

import "errors"

var myMateChatFiltersMapDatastore *myMap.MyMap
var myModeratorChatFiltersMapDatastore *myMap.MyMap

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

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

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

	myMateChatFiltersMapDatastore = newMyMateChatFiltersMapDatastore
	myModeratorChatFiltersMapDatastore = newMyModeratorChatFiltersMapDatastore

	return nil
}

func getMyChatFiltersMapDatastore(identityType string)(*myMap.MyMap, error){

	if (identityType == "Mate"){
		return myMateChatFiltersMapDatastore, nil
	}
	if (identityType == "Moderator"){
		return myModeratorChatFiltersMapDatastore, nil
	}

	return nil, errors.New("getMyChatFilterMapDatastore called with invalid identityType: " + identityType)
}

// Returns a list of all chat filters for the requested identityType
func GetChatFiltersList(identityType string)([]string, error){

	if (identityType != "Mate" && identityType != "Moderator"){
		return nil, errors.New("GetChatFiltersList called with invalid identityType: " + identityType)
	}

	if (identityType == "Mate"){

		allMateChatFiltersList := []string{"ShowMyContactsOnly", "ShowMyMatchesOnly", "ShowHasMessagedMeOnly", "OnlyShowLikedUsers", "HideIgnoredUsers"}

		return allMateChatFiltersList, nil
	}

	allModeratorChatFiltersList := []string{"ShowMyContactsOnly", "ShowHasMessagedMeOnly"}

	return allModeratorChatFiltersList, nil
}

// Outputs:
//	-bool: User passes filters
//	-error
func CheckIfUserPassesAllMyChatFilters(userIdentityHash [16]byte, networkType byte)(bool, error){

	userIdentityType, err := identity.GetIdentityTypeFromIdentityHash(userIdentityHash)
	if (err != nil){
		userIdentityHashHex := encoding.EncodeBytesToHexString(userIdentityHash[:])
		return false, errors.New("CheckIfUserPassesAllMyChatFilters called with invalid identity hash: " + userIdentityHashHex)
	}

	if (userIdentityType == "Host"){
		return false, errors.New("CheckIfUserPassesAllMyChatFilters called with Host user.")
	}

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

	chatFiltersList, err := GetChatFiltersList(userIdentityType)
	if (err != nil) { return false, err }

	for _, chatFilterName := range chatFiltersList{

		passesDesire, err := checkIfUserPassesMyChatFilter(userIdentityHash, networkType, chatFilterName)
		if (err != nil) { return false, err }
		if (passesDesire == false){
			return false, nil
		}
	}

	return true, nil
}


//Outputs:
//	-map[string]bool: Chat filter name -> User passes chat filter
//	-error
func GetUserPassesMyChatFiltersMap(userIdentityHash [16]byte, networkType byte)(map[string]bool, error){

	userIdentityType, err := identity.GetIdentityTypeFromIdentityHash(userIdentityHash)
	if (err != nil){
		userIdentityHashHex := encoding.EncodeBytesToHexString(userIdentityHash[:])
		return nil, errors.New("GetUserPassesMyChatFiltersMap called with invalid identity hash: " + userIdentityHashHex)
	}

	if (userIdentityType == "Host"){
		return nil, errors.New("GetUserPassesMyChatFiltersMap called with Host user.")
	}

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

	chatFiltersList, err := GetChatFiltersList(userIdentityType)
	if (err != nil) { return nil, err }

	// Map Structure: Chat filter name -> User passes filter
	userPassesChatFiltersMap := make(map[string]bool)

	for _, chatFilterName := range chatFiltersList{

		userPassesFilter, err := checkIfUserPassesMyChatFilter(userIdentityHash, networkType, chatFilterName)
		if (err != nil) { return nil, err }
		
		userPassesChatFiltersMap[chatFilterName] = userPassesFilter
	}

	return userPassesChatFiltersMap, nil
}
	
	
func checkIfUserPassesMyChatFilter(userIdentityHash [16]byte, networkType byte, chatFilterName string)(bool, error){

	userIdentityType, err := identity.GetIdentityTypeFromIdentityHash(userIdentityHash)
	if (err != nil) {
		userIdentityHashHex := encoding.EncodeBytesToHexString(userIdentityHash[:])
		return false, errors.New("checkIfUserPassesMyChatFilter called with invalid identity hash: " + userIdentityHashHex)
	}

	if (userIdentityType == "Host"){
		return false, errors.New("checkIfUserPassesMyChatFilter called with Host user.")
	}

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

	chatFilterIsEnabled, err := GetChatFilterOnOffStatus(userIdentityType, chatFilterName)
	if (err != nil) { return false, err }
	if (chatFilterIsEnabled == false){
		return true, nil
	}

	if (chatFilterName == "ShowMyContactsOnly"){

		isMyContact, err := myContacts.CheckIfUserIsMyContact(userIdentityHash)
		if (err != nil) { return false, err }
		if (isMyContact == false){
			return false, nil
		}

		return true, nil
	}
	if (chatFilterName == "ShowMyMatchesOnly"){

		profileExists, _, getAnyUserAttributeFunction, err := viewableProfiles.GetRetrieveAnyNewestViewableUserProfileAttributeFunction(userIdentityHash, networkType, true, false, false)
		if (err != nil) { return false, err }
		if (profileExists == false) {
			// Profile not found.
			return false, nil
		}

		passesMyDesires, err := myMateDesires.CheckIfMateProfilePassesAllMyDesires(false, "", getAnyUserAttributeFunction)
		if (err != nil) { return false, err }
		if (passesMyDesires == false){
			return false, nil
		}

		return true, nil
	}
	if (chatFilterName == "ShowHasMessagedMeOnly"){

		hasMessagedMeStatus, err := myChatMessages.CheckIfUserHasMessagedMe(userIdentityHash, networkType)
		if (err != nil) { return false, err }
		if (hasMessagedMeStatus == false){
			return false, nil
		}

		return true, nil
	}

	if (chatFilterName == "OnlyShowLikedUsers"){
	
		userIsLiked, _, err := myLikedUsers.CheckIfUserIsLiked(userIdentityHash)
		if (err != nil) { return false, err }
		if (userIsLiked == false){
			return false, nil
		}

		return true, nil
	}
	if (chatFilterName == "HideIgnoredUsers"){

		userIsIgnored, _, _, _, err := myIgnoredUsers.CheckIfUserIsIgnored(userIdentityHash)
		if (err != nil) { return false, err }
		if (userIsIgnored == true){
			return false, nil
		}

		return true, nil
	}

	return false, errors.New("checkIfUserPassesMyChatFilter called with invalid chatFilterName: " + chatFilterName)
}


func GetNumberOfEnabledChatFilters(myIdentityType string)(int, error){

	myEnabledChatFiltersList, err := GetAllMyEnabledChatFiltersList(myIdentityType)
	if (err != nil) { return 0, err }

	numberOfEnabledFilters := len(myEnabledChatFiltersList)
	
	return numberOfEnabledFilters, nil
}

func GetAllMyEnabledChatFiltersList(myIdentityType string)([]string, error){

	chatFiltersList, err := GetChatFiltersList(myIdentityType)
	if (err != nil) { return nil, err }

	myEnabledChatFiltersList := make([]string, 0)

	for _, chatFilterName := range chatFiltersList{

		currentOnOffStatus, err := GetChatFilterOnOffStatus(myIdentityType, chatFilterName)
		if (err != nil) { return nil, err }

		if (currentOnOffStatus == true){
			myEnabledChatFiltersList = append(myEnabledChatFiltersList, chatFilterName)
		}
	}
	
	return myEnabledChatFiltersList, nil
}

func SetChatFilterOnOffStatus(myIdentityType string, chatFilterName string, chatFilterStatus bool)error{

	if (myIdentityType != "Mate" && myIdentityType != "Moderator") {
		return errors.New("SetChatFilterOnOffStatus called with invalid identity type: " + myIdentityType)
	}

	filterOnOffStatusString := helpers.ConvertBoolToYesOrNoString(chatFilterStatus)

	myChatFiltersMapDatastore, err := getMyChatFiltersMapDatastore(myIdentityType)
	if (err != nil){ return err }

	err = myChatFiltersMapDatastore.SetMapEntry(chatFilterName, filterOnOffStatusString)
	if (err != nil) { return err }

	err = mySettings.SetSetting(myIdentityType + "ChatConversationsGeneratedStatus", "No")
	if (err != nil) { return err }

	return nil
}


func GetChatFilterOnOffStatus(myIdentityType string, chatFilterName string)(bool, error){

	if (myIdentityType != "Mate" && myIdentityType != "Moderator") {
		return false, errors.New("GetChatFilterOnOffStatus called with invalid identity type: " + myIdentityType)
	}

	myChatFiltersMapDatastore, err := getMyChatFiltersMapDatastore(myIdentityType)
	if (err != nil){ return false, err }

	filterStatusExists, currentFilterStatus, err := myChatFiltersMapDatastore.GetMapEntry(chatFilterName)
	if (err != nil) { return false, err }
	if (filterStatusExists == false){

		if (chatFilterName == "HideIgnoredUsers"){
			return true, nil
		}
		return false, nil
	}

	filterOnOffStatusBool, err := helpers.ConvertYesOrNoStringToBool(currentFilterStatus)
	if (err != nil) { return false, err }

	return filterOnOffStatusBool, nil
}





