
// myChatFilterStatistics provides functions to create statistics based on a user's chat filters.
// These statistics will show the user what percentage of their conversations are being filtered by their chat filters.

package myChatFilterStatistics

import "seekia/internal/helpers"
import "seekia/internal/identity"
import "seekia/internal/messaging/myChatFilters"
import "seekia/internal/messaging/myChatMessages"
import "seekia/internal/myBlockedUsers"
import "seekia/internal/myIdentity"

import "errors"

type ChatFilterStatisticsItem struct{

	// The name of the filter
	// Example: "ShowMyMatchesOnly"
	FilterName string

	// How many recipients pass the filter
	NumberOfRecipientsWhoPassFilter int

	// Percentage of all chat recipients who pass filter
	PercentageOfRecipientsWhoPassFilter float64

	// How many filtered recipients you would have if this filter was deactivated
	NumberOfFilterExcludedRecipients int

	// What percentage of filter-excluded filtered recipients pass this filter
	PercentageOfFilterExcludedRecipientsWhoPassFilter float64
}

//Outputs:
//	-int: Number of conversations (Number of Recipients)
//	-int: Number of conversations which pass all chat filters
//	-[]ChatFilterStatisticsItem
//	-error
func GetAllMyChatFilterStatistics(myIdentityType string, networkType byte)(int, int, []ChatFilterStatisticsItem, error){

	if (myIdentityType != "Mate" && myIdentityType != "Moderator"){
		return 0, 0, nil, errors.New("Invalid myIdentityType in call to GetAllMyChatFilterStatistics: " + myIdentityType)
	}

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

	myIdentityExists, myIdentityHash, err := myIdentity.GetMyIdentityHash(myIdentityType)
	if (err != nil) { return 0, 0, nil, err }

	updatePercentageProgress := func(_ int)error{
		return nil
	}

	myChatMessagesMapList, err := myChatMessages.GetUpdatedMyChatMessagesMapList(myIdentityType, networkType, updatePercentageProgress)
	if (err != nil) { return 0, 0, nil, err }

	// We use a map to avoid duplicates
	allRecipientsMap := make(map[[16]byte]struct{})

	for _, chatMessageMap := range myChatMessagesMapList{

		if (myIdentityExists == false){
			// No messages or conversations exist.
			break
		}

		messageMyIdentityHashString, exists := chatMessageMap["MyIdentityHash"]
		if (exists == false){
			return 0, 0, nil, errors.New("Malformed message map: missing MyIdentityHash.")
		}

		messageMyIdentityHash, _, err := identity.ReadIdentityHashString(messageMyIdentityHashString)
		if (err != nil){
			return 0, 0, nil, errors.New("Malformed message map: Contains invalid MyIdentityHash: " + messageMyIdentityHashString)
		}

		if (messageMyIdentityHash != myIdentityHash){
			// This should not happen
			// If we delete our identity, we will prune any messages for that identity from our chat messages map
			//TODO: Log this
			continue
		}

		theirIdentityHashString, exists := chatMessageMap["TheirIdentityHash"]
		if (exists == false){
			return 0, 0, nil, errors.New("MyChatMessages map malformed: missing TheirIdentityHash")
		}

		theirIdentityHash, _, err := identity.ReadIdentityHashString(theirIdentityHashString)
		if (err != nil){
			return 0, 0, nil, errors.New("Malformed message map: Contains invalid TheirIdentityHash: " + theirIdentityHashString)
		}

		theyAreBlocked, _, _, _, err := myBlockedUsers.CheckIfUserIsBlocked(theirIdentityHash)
		if (err != nil) { return 0, 0, nil, err }
		if (theyAreBlocked == true) {
			continue
		}

		allRecipientsMap[theirIdentityHash] = struct{}{}
	}

	allRecipientsList := helpers.GetListOfMapKeys(allRecipientsMap)

	numberOfRecipients := len(allRecipientsList)

	// Below will store the number of recipients who pass all chat filters
	numberOfFilteredRecipients := 0

	//Map Structure: Filter name -> Number of recipients who pass filter
	numberOfRecipientsWhoPassFilterMap := make(map[string]int)

	//Map Structure: Filter name -> Number of filtered recipients the user would have excluding the filter
	numberOfFilterExcludedRecipientsMap := make(map[string]int)

	for _, recipientIdentityHash := range allRecipientsList{

		recipientPassesAllFilters := true

		userPassesMyFiltersMap, err := myChatFilters.GetUserPassesMyChatFiltersMap(recipientIdentityHash, networkType)
		if (err != nil) { return 0, 0, nil, err }

		for filterName, userPassesFilter := range userPassesMyFiltersMap{

			if (userPassesFilter == true){

				numberOfRecipientsWhoPassFilterMap[filterName] += 1
			} else {
				recipientPassesAllFilters = false
			}

			// Now we find out if recipient would pass all filters excluding current filter

			checkIfRecipientPassesFiltersExcludingCurrent := func()bool{

				for filterNameInner, userPassesFilterInner := range userPassesMyFiltersMap{

					if (filterNameInner == filterName){
						continue
					}
					if (userPassesFilterInner == false){
						return false
					}
				}

				return true
			}

			recipientPassesFiltersExcludingCurrent := checkIfRecipientPassesFiltersExcludingCurrent()

			if (recipientPassesFiltersExcludingCurrent == true){
				numberOfFilterExcludedRecipientsMap[filterName] += 1
			}
		}

		if (recipientPassesAllFilters == true){
			numberOfFilteredRecipients += 1
		}
	}

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

	allMyChatFilterStatisticsItemsList := make([]ChatFilterStatisticsItem, 0, len(chatFiltersList))

	for _, filterName := range chatFiltersList{

		getNumberOfRecipientsWhoPassFilter := func()int{

			numberOfRecipientsWhoPassFilter, exists := numberOfRecipientsWhoPassFilterMap[filterName]
			if (exists == false) {
				return 0
			}
			return numberOfRecipientsWhoPassFilter
		}

		numberOfRecipientsWhoPassFilter := getNumberOfRecipientsWhoPassFilter()

		getNumberOfFilterExcludedRecipients := func()int{

			numberOfFilterExcludedRecipients, exists := numberOfFilterExcludedRecipientsMap[filterName]
			if (exists == false) {
				return 0
			}

			return numberOfFilterExcludedRecipients
		}

		numberOfFilterExcludedRecipients := getNumberOfFilterExcludedRecipients()

		getPercentageOfRecipientsWhoPassFilter := func()float64{
			if (numberOfRecipients == 0){
				return 0
			}

			percentageOfRecipientsWhoPassFilter := 100 * (float64(numberOfRecipientsWhoPassFilter)/float64(numberOfRecipients))

			return percentageOfRecipientsWhoPassFilter
		}

		percentageOfRecipientsWhoPassFilter := getPercentageOfRecipientsWhoPassFilter()

		getPercentageOfFilterExcludedRecipientsWhoPassFilter := func()float64{
			if (numberOfRecipients == 0){
				return 0
			}

			percentageOfFilterExcludedRecipientsWhoPassFilter := 100 * (float64(numberOfFilteredRecipients)/float64(numberOfFilterExcludedRecipients))

			return percentageOfFilterExcludedRecipientsWhoPassFilter
		}

		percentageOfFilterExcludedRecipientsWhoPassFilter := getPercentageOfFilterExcludedRecipientsWhoPassFilter()

		newStatisticsItem := ChatFilterStatisticsItem{
			FilterName: filterName,
			NumberOfRecipientsWhoPassFilter: numberOfRecipientsWhoPassFilter,
			PercentageOfRecipientsWhoPassFilter: percentageOfRecipientsWhoPassFilter,
			NumberOfFilterExcludedRecipients: numberOfFilterExcludedRecipients,
			PercentageOfFilterExcludedRecipientsWhoPassFilter: percentageOfFilterExcludedRecipientsWhoPassFilter,
		}

		allMyChatFilterStatisticsItemsList = append(allMyChatFilterStatisticsItemsList, newStatisticsItem)
	}

	return numberOfRecipients, numberOfFilteredRecipients, allMyChatFilterStatisticsItemsList, nil
}




