package gui

// desireStatisticsGui.go implements pages to view a user's desire statistics

import "fyne.io/fyne/v2"
import "fyne.io/fyne/v2/container"
import "fyne.io/fyne/v2/data/binding"
import "fyne.io/fyne/v2/layout"
import "fyne.io/fyne/v2/theme"
import "fyne.io/fyne/v2/widget"

import "seekia/internal/appMemory"
import "seekia/internal/desires/mateDesires"
import "seekia/internal/desires/myDesireStatistics"
import "seekia/internal/desires/myLocalDesires"
import "seekia/internal/helpers"
import "seekia/internal/network/appNetworkType/getAppNetworkType"

import "time"
import "errors"

// This page is used to view the statistics of a single desire
func setViewMyMateDesireStatisticsPage(window fyne.Window, desireTitle string, desireName string, showChartsButton bool, barOrDonutChart string, attributeName string, previousPage func()){

	currentPage := func(){setViewMyMateDesireStatisticsPage(window, desireTitle, desireName, showChartsButton, barOrDonutChart, attributeName, previousPage)}

	// We use a page identifier to uniquely identify this page and detect if the user is still viewing the page
	// If the user leaves this page before the getStatistics goroutine is complete, once it completes, the page will not refresh

	pageIdentifier, err := helpers.GetNewRandomHexString(16)
	if (err != nil) {
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	appMemory.SetMemoryEntry("CurrentViewedPage", pageIdentifier)

	checkIfPageHasChangedFunction := func()bool{
		exists, currentViewedPage := appMemory.GetMemoryEntry("CurrentViewedPage")
		if (exists == true && currentViewedPage == pageIdentifier){
			return false
		}
		return true
	}

	title := getPageTitleCentered("My Desire Statistics - " + desireTitle)

	backButton := getBackButtonCentered(previousPage)

	viewChartsFunction := func(){

		if (showChartsButton == false){
			return
		}
		if (barOrDonutChart == "Bar"){

			setViewUserAttributeStatisticsPage_BarChart(window, "Mate", attributeName, "Number Of Users", " Users", true, false, false, nil, false, nil, nil, currentPage)

			return
		}
		if (barOrDonutChart == "Donut"){

			setViewUserAttributeStatisticsPage_DonutChart(window, "Mate", attributeName, false, false, nil, false, nil, nil, currentPage)

			return
		}
		setErrorEncounteredPage(window, errors.New("setViewMyMateDesireStatisticsPage called with invalid barOrDonutChart: " + barOrDonutChart), currentPage)
	}

	//Outputs:
	//	-bool: Desire is disabled
	//	-bool: Filter All is disabled
	//	-bool: Require Response is disabled
	//	-error
	getDesireIsDisabledStatus := func()(bool, bool, bool, error){

		getFilterAllIsEnabledBool := func()(bool, error){

			exists, currentFilterAllSetting, err := myLocalDesires.GetDesire(desireName + "_FilterAll")
			if (err != nil) { return false, err }
			if (exists == true && currentFilterAllSetting == "Yes"){
				return true, nil
			}
			return false, nil
		}

		filterAllIsEnabled, err := getFilterAllIsEnabledBool()
		if (err != nil) { return false, false, false, err }
		if (filterAllIsEnabled == true){
			// Desire is enabled
			return false, false, false, nil
		}

		// Most desires allow the user to enable Require Response, which filters user who did not respond
		allowsRequireResponse, _ := mateDesires.CheckIfDesireAllowsRequireResponse(desireName)
		if (allowsRequireResponse == false){
			// Desire is disabled, no users will be filtered
			return true, true, false, nil
		}

		getRequireResponseIsEnabledBool := func()(bool, error){

			exists, currentRequireResponse, err := myLocalDesires.GetDesire(desireName + "_RequireResponse")
			if (err != nil) { return false, err }
			if (exists == true && currentRequireResponse == "Yes"){
				return true, nil
			}

			return false, nil
		}

		requireResponseIsEnabled, err := getRequireResponseIsEnabledBool()
		if (err != nil) { return false, false, false, err }
		if (requireResponseIsEnabled == true){
			// Desire is enabled, because we require a response
			return false, false, false, nil
		}

		// FilterAll and RequireResponse are both disabled, thus the desire is disabled

		return true, true, true, nil
	}

	desireIsDisabled, filterAllIsDisabled, requireResponseIsDisabled, err := getDesireIsDisabledStatus()
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}
	if (desireIsDisabled == true){

		getDisabledOptionsString := func()string{

			if (filterAllIsDisabled == true && requireResponseIsDisabled == true){

				return "Filter All or Require Response"
			}
			// filterAllIsDisabled == true && requireResponseIsDisabled == false

			return "Filter All"
		}

		disabledOptionsString := getDisabledOptionsString()

		description1 := getBoldLabelCentered("You do not have " + disabledOptionsString + " enabled for this desire.")
		description2 := getLabelCentered("This means that all users will pass the desire.")

		description3Label := getLabelCentered("Without " + disabledOptionsString + " enabled, the desire only impacts user match scores.")
		filterOptionsHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
				setDesireFilterOptionsExplainerPage(window, currentPage)
			})
		description3Row := container.NewHBox(layout.NewSpacer(), description3Label, filterOptionsHelpButton, layout.NewSpacer())

		page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3Row)

		if (showChartsButton == true){

			page.Add(widget.NewSeparator())
			description4 := getLabelCentered("Visualize the distribution of user responses on a chart.")
			page.Add(description4)

			viewChartButton := getWidgetCentered(widget.NewButtonWithIcon("View Chart", theme.InfoIcon(), viewChartsFunction))
			page.Add(viewChartButton)
		}

		setPageContent(page, window)
		return
	}

	appNetworkType, err := getAppNetworkType.GetAppNetworkType()
	if (err != nil) {
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	allIdentitiesStatisticsBinding := binding.NewString()
	matchStatisticsBinding := binding.NewString()

	updateBindingsFunction := func(){

		statisticsFound := false

		updateBindingsWithProgressEllipsesFunction := func(){

			secondsElapsed := 0

			for {
				if (statisticsFound == true){
					return
				}
				pageHasChanged := checkIfPageHasChangedFunction()
				if (pageHasChanged == true){
					return
				}

				if (secondsElapsed % 3 == 0){
					allIdentitiesStatisticsBinding.Set("Loading.")
					matchStatisticsBinding.Set("Loading.")
				} else if (secondsElapsed %3 == 1){
					allIdentitiesStatisticsBinding.Set("Loading..")
					matchStatisticsBinding.Set("Loading..")
				} else {
					allIdentitiesStatisticsBinding.Set("Loading...")
					matchStatisticsBinding.Set("Loading...")
				}

				time.Sleep(time.Second)
				secondsElapsed += 1
			}
		}

		go updateBindingsWithProgressEllipsesFunction()

		totalNumberOfMateIdentities, numberOfMateIdentitiesWhoPassDesire, percentageOfMateIdentitiesWhoPassDesire, numberOfMatches, numberOfMatchesWhoPassDesire, percentageOfMatchesWhoPassDesire, err := myDesireStatistics.GetMyDesireStatistics(desireName, appNetworkType)
		if (err != nil){
			fyne.Do(func(){setErrorEncounteredPage(window, err, previousPage)})
			return
		}

		statisticsFound = true

		totalNumberOfMateIdentitiesString := helpers.ConvertInt64ToString(totalNumberOfMateIdentities)
		numberOfMateIdentitiesWhoPassDesireString := helpers.ConvertInt64ToString(numberOfMateIdentitiesWhoPassDesire)
		percentageOfMateIdentiesWhoPassDesireString := helpers.ConvertFloat64ToStringRounded(percentageOfMateIdentitiesWhoPassDesire, 1)

		numberOfMatchesString := helpers.ConvertInt64ToString(numberOfMatches)
		numberOfMatchesWhoPassDesireString := helpers.ConvertInt64ToString(numberOfMatchesWhoPassDesire)
		percentageOfMatchesWhoPassDesireString := helpers.ConvertFloat64ToStringRounded(percentageOfMatchesWhoPassDesire, 1)

		allIdentitiesStatisticsString := numberOfMateIdentitiesWhoPassDesireString + "/" + totalNumberOfMateIdentitiesString + " = " + percentageOfMateIdentiesWhoPassDesireString + "%"

		matchesStatisticsString :=  numberOfMatchesWhoPassDesireString + "/" + numberOfMatchesString + " = " + percentageOfMatchesWhoPassDesireString + "%"

		allIdentitiesStatisticsBinding.Set(allIdentitiesStatisticsString)
		matchStatisticsBinding.Set(matchesStatisticsString)
	}

	description1 := getLabelCentered("Below are your " + desireTitle + " desire statistics.")
	description2 := getLabelCentered("They are the statistics of the users who pass your " + desireTitle + " desires.")
	description3 := getLabelCentered("My Matches divides by the number of matches you would have without the desire.")

	allUsersLabel := getBoldLabelCentered("All Users:")

	allIdentitiesStatisticsLabel := getWidgetCentered(widget.NewLabelWithData(allIdentitiesStatisticsBinding))

	myMatchesLabel := getBoldLabelCentered("My Matches:")

	matchIdentitiesStatisticsLabel := getWidgetCentered(widget.NewLabelWithData(matchStatisticsBinding))

	accuracyWarningButton := getWidgetCentered(widget.NewButtonWithIcon("Statistics Warning", theme.WarningIcon(), func(){
			setMateDesireStatisticsWarningPage(window, currentPage)
		}))

	page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3, widget.NewSeparator(), allUsersLabel, allIdentitiesStatisticsLabel, myMatchesLabel, matchIdentitiesStatisticsLabel, widget.NewSeparator(), accuracyWarningButton)

	if (showChartsButton == true){

		page.Add(widget.NewSeparator())

		description4 := getLabelCentered("Visualize the distribution of users on a chart.")
		page.Add(description4)

		viewChartButton := getWidgetCentered(widget.NewButtonWithIcon("View Chart", theme.InfoIcon(), viewChartsFunction))
		page.Add(viewChartButton)
	}

	setPageContent(page, window)

	go updateBindingsFunction()	
}



func setViewAllMyDesireStatisticsPage(window fyne.Window, statisticsReady bool, numberOfMateIdentities int64, numberOfMatches int64, statisticsItemsList []myDesireStatistics.DesireStatisticsItem, previousPage func()){

	pageIdentifier, err := helpers.GetNewRandomHexString(16)
	if (err != nil) {
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	appMemory.SetMemoryEntry("CurrentViewedPage", pageIdentifier)

	checkIfPageHasChangedFunction := func()bool{
		exists, currentViewedPage := appMemory.GetMemoryEntry("CurrentViewedPage")
		if (exists == true && currentViewedPage == pageIdentifier){
			return false
		}
		return true
	}

	currentPage := func(){setViewAllMyDesireStatisticsPage(window, statisticsReady, numberOfMateIdentities, numberOfMatches, statisticsItemsList, previousPage)}

	title := getPageTitleCentered("My Mate Desire Statistics")

	backButton := getBackButtonCentered(previousPage)

	if (statisticsReady == false){

		appNetworkType, err := getAppNetworkType.GetAppNetworkType()
		if (err != nil) {
			setErrorEncounteredPage(window, err, previousPage)
			return
		}

		loadingTextBinding := binding.NewString()
		loadingTextBinding.Set("Loading Statistics...")

		loadingProgressBinding := binding.NewString()
		
		loadingTextLabel := widget.NewLabelWithData(loadingTextBinding)
		loadingTextLabel.TextStyle = getFyneTextStyle_Bold()
		loadingTextLabelCentered := getWidgetCentered(loadingTextLabel)

		loadingProgressLabel := getWidgetCentered(widget.NewLabelWithData(loadingProgressBinding))

		calculateStatisticsAndRefreshPageFunction := func(){

			progressIdentifier, _ := helpers.GetNewRandomHexString(16)			

			statisticsComplete := false

			updateLoadingBindingFunction := func(){

				startTime := time.Now().Unix()

				for {

					currentTime := time.Now().Unix()
					secondsElapsed := currentTime - startTime

					if (secondsElapsed % 3 == 0){
						loadingTextBinding.Set("Loading Statistics.")	
					} else if (secondsElapsed % 3 == 1){
						loadingTextBinding.Set("Loading Statistics..")
					} else {
						loadingTextBinding.Set("Loading Statistics...")
					}

					statusExists, newProgressStatus := appMemory.GetMemoryEntry(progressIdentifier)
					if (statusExists == true){
						loadingProgressBinding.Set(newProgressStatus)
					}

					pageHasChanged := checkIfPageHasChangedFunction()
					if (pageHasChanged == true){
						return
					}

					if (statisticsComplete == true){
						return
					}

					time.Sleep(100 * time.Millisecond)
				}
			}

			go updateLoadingBindingFunction()

			numberOfMateIdentities, numberOfMatches, myDesireStatisticsItemsList, err := myDesireStatistics.GetAllMyDesireStatistics(progressIdentifier, appNetworkType)
			if (err != nil) {
				statisticsComplete = true
				pageHasChanged := checkIfPageHasChangedFunction()
				if (pageHasChanged == false){
					fyne.Do(func(){setErrorEncounteredPage(window, err, previousPage)})
				}
				return
			}

			statisticsComplete = true

			pageHasChanged := checkIfPageHasChangedFunction()
			if (pageHasChanged == false){
				fyne.Do(func(){setViewAllMyDesireStatisticsPage(window, true, numberOfMateIdentities, numberOfMatches, myDesireStatisticsItemsList, previousPage)})
			}
		}

		page := container.NewVBox(title, backButton, widget.NewSeparator(), loadingTextLabelCentered, loadingProgressLabel)

		setPageContent(page, window)

		go calculateStatisticsAndRefreshPageFunction()
		return
	}

	if (numberOfMateIdentities == 0){

		description1 := getBoldLabelCentered("You have no Mate profiles downloaded.")
		description2 := getLabelCentered("No desire statistics are available.")

		page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2)

		setPageContent(page, window)
		return
	}

	setLoadingScreen(window, "My Mate Desire Statistics", "Loading desire statistics...")

	getStatisticsSection := func()(*fyne.Container, error){

		// These are the desires for which FilterAll and Require Response is disabled
		// These desires will not filter any matches. They only effect match score
		disabledDesiresList := make([]string, 0)

		desireNameLabel := getItalicLabelCentered("Desire Name")
		allUsersLabel := getItalicLabelCentered("All Users")
		myMatchesLabel := getItalicLabelCentered("My Matches")

		desireTitlesColumn := container.NewVBox(desireNameLabel, widget.NewSeparator())
		allUsersColumn := container.NewVBox(allUsersLabel, widget.NewSeparator())
		myMatchesColumn := container.NewVBox(myMatchesLabel, widget.NewSeparator())

		numberOfMateIdentitiesString := helpers.ConvertInt64ToString(numberOfMateIdentities)
		numberOfMatchesString := helpers.ConvertInt64ToString(numberOfMatches)

		for _, desireObject := range statisticsItemsList{

			desireName := desireObject.DesireName
			numberOfUsersWhoPassDesire := desireObject.NumberOfUsersWhoPassDesire
			percentageOfUsersWhoPassDesire := desireObject.PercentageOfUsersWhoPassDesire
			numberOfDesireExcludedMatches := desireObject.NumberOfDesireExcludedMatches
			percentageOfDesireExcludedMatchesWhoPassDesire := desireObject.PercentageOfDesireExcludedMatchesWhoPassDesire

			desireTitle, err := mateDesires.GetDesireTitleFromDesireName(desireName)
			if (err != nil){ return nil, err }

			desireTitleTranslated := translate(desireTitle)

			checkIfDesireIsDisabled := func()(bool, error){

				exists, filterAllStatus, err := myLocalDesires.GetDesire(desireName + "_FilterAll")
				if (err != nil) { return false, err }
				if (exists == true && filterAllStatus == "Yes"){
					return false, nil
				}

				requireResponseAllowed, _ := mateDesires.CheckIfDesireAllowsRequireResponse(desireName)
				if (requireResponseAllowed == true){

					exists, requireResponseStatus, err := myLocalDesires.GetDesire(desireName + "_RequireResponse")
					if (err != nil) { return false, err }
					if (exists == true && requireResponseStatus == "Yes"){
						return false, nil
					}
				}

				// Desire is disabled
				// We use 99.9 because floating point is not exact, we really mean 100%.
				if (percentageOfUsersWhoPassDesire < 99.9){
					return false, errors.New("Disabled desire does not have a 100% pass rate: " + desireName)
				}	

				return true, nil
			}

			desireIsDisabled, err := checkIfDesireIsDisabled()	
			if (err != nil) { return nil, err }
			if (desireIsDisabled == true){
				disabledDesiresList = append(disabledDesiresList, desireTitleTranslated)
				continue
			}

			desireTitleLabel := getBoldLabelCentered(desireTitleTranslated)

			numberOfUsersWhoPassDesireString := helpers.ConvertInt64ToString(numberOfUsersWhoPassDesire)
			percentageOfUsersWhoPassDesireString := helpers.ConvertFloat64ToStringRounded(percentageOfUsersWhoPassDesire, 1)
			numberOfDesireExcludedMatchesString := helpers.ConvertInt64ToString(numberOfDesireExcludedMatches)
			percentageOfDesireExcludedMatchesWhoPassDesireString := helpers.ConvertFloat64ToStringRounded(percentageOfDesireExcludedMatchesWhoPassDesire, 1)

			allUsersLabel := getBoldLabelCentered(numberOfUsersWhoPassDesireString + "/" + numberOfMateIdentitiesString + " = " + percentageOfUsersWhoPassDesireString + "%")

			matchesLabel := getBoldLabelCentered(numberOfMatchesString + "/" + numberOfDesireExcludedMatchesString + " = " + percentageOfDesireExcludedMatchesWhoPassDesireString + "%")

			desireTitlesColumn.Add(desireTitleLabel)
			allUsersColumn.Add(allUsersLabel)
			myMatchesColumn.Add(matchesLabel)

			desireTitlesColumn.Add(widget.NewSeparator())
			allUsersColumn.Add(widget.NewSeparator())
			myMatchesColumn.Add(widget.NewSeparator())
		}

		numberOfDisabledDesires := len(disabledDesiresList)

		if (numberOfDisabledDesires == len(statisticsItemsList)){

			description1 := getBoldLabelCentered("All of your desires are disabled.")
			description2 := getLabelCentered("None of your desires have Filter All or Require Response enabled.")
			description3 := getLabelCentered("All users are your matches.")

			viewDisabledDesiresButton := getWidgetCentered(widget.NewButtonWithIcon("View Disabled Desires", theme.VisibilityIcon(), func(){
				setViewAllMyDisabledDesiresPage(window, disabledDesiresList, currentPage)
			}))

			statisticsSection := container.NewVBox(description1, description2, description3, viewDisabledDesiresButton)

			return statisticsSection, nil
		}

		description1 := getLabelCentered("Below are the percentages of users who pass each of your desires.")
		description2 := getLabelCentered("My Matches divides by the number of matches you would have without the desire.")

		accuracyWarningButton := getWidgetCentered(widget.NewButtonWithIcon("Statistics Warning", theme.WarningIcon(), func(){
				setMateDesireStatisticsWarningPage(window, currentPage)
			}))

		statisticsGrid := container.NewHBox(layout.NewSpacer(), desireTitlesColumn, allUsersColumn, myMatchesColumn, layout.NewSpacer())

		numberOfDisabledDesiresString := helpers.ConvertIntToString(numberOfDisabledDesires)

		disabledDesiresDescription1 := getBoldLabelCentered("There are " + numberOfDisabledDesiresString + " desires with Filter All and Require Response disabled.")
		disabledDesiresDescription2 := getLabelCentered("These desires do not filter any matches.")

		viewDisabledDesiresButton := getWidgetCentered(widget.NewButtonWithIcon("View Disabled Desires", theme.VisibilityIcon(), func(){
				setViewAllMyDisabledDesiresPage(window, disabledDesiresList, currentPage)
			}))

		statisticsSection := container.NewVBox(description1, description2, widget.NewSeparator(), accuracyWarningButton, widget.NewSeparator(), statisticsGrid, widget.NewSeparator(), disabledDesiresDescription1, disabledDesiresDescription2, viewDisabledDesiresButton)

		return statisticsSection, nil
	}

	statisticsSection, err := getStatisticsSection()
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	page := container.NewVBox(title, backButton, widget.NewSeparator(), statisticsSection)

	setPageContent(page, window)
}


func setViewAllMyDisabledDesiresPage(window fyne.Window, disabledDesiresList []string, previousPage func()){

	title := getPageTitleCentered("My Mate Desire Statistics")

	backButton := getBackButtonCentered(previousPage)

	subtitle := getPageSubtitleCentered("Disabled Desires")

	description1 := getLabelCentered("Below are your desires with Filter All and Require Response disabled.")
	description2 := getLabelCentered("They will not filter any matches.")
	description3 := getLabelCentered("They will only effect match scores.")

	disabledDesiresGrid := container.NewGridWithColumns(2)

	for _, desireTitle := range disabledDesiresList{

		desireTitleLabel := getBoldLabelCentered(desireTitle)
		
		disabledDesiresGrid.Add(desireTitleLabel)	
	}

	disabledDesiresGridCentered := getContainerCentered(disabledDesiresGrid)

	page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, widget.NewSeparator(), disabledDesiresGridCentered)

	setPageContent(page, window)
}


