package gui

// viewModeratorsGui.go implements a page to browse moderators

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

import "seekia/internal/appMemory"
import "seekia/internal/helpers"
import "seekia/internal/identity"
import "seekia/internal/moderation/viewedModerators"
import "seekia/internal/mySettings"
import "seekia/internal/network/appNetworkType/getAppNetworkType"
import "seekia/internal/profiles/viewableProfiles"

import "time"
import "errors"


func setViewModeratorsPage(window fyne.Window, previousPage func()){

	appMemory.SetMemoryEntry("CurrentViewedPage", "ViewModerators")

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

	//TODO: Check if moderator/host mode is enabled
	// If not, many attributes cannot be displayed, and the list will be empty/outdated
	// Require either mode to be enabled to view moderators

	currentPage := func(){setViewModeratorsPage(window, previousPage)}

	title := getPageTitleCentered("Viewing Moderators")
	
	backButton := getBackButtonCentered(previousPage)

	filtersIcon, err := getFyneImageIcon("Desires")
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}
	filtersButton := widget.NewButton("Filters", func(){
			//TODO
			showUnderConstructionDialog(window)
		})
	filtersButtonWithIcon := container.NewGridWithRows(2, filtersIcon, filtersButton)

	statsIcon, err := getFyneImageIcon("Stats")
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}
	statsButton := widget.NewButton("Stats", func(){
			//TODO
			showUnderConstructionDialog(window)
		})
	statsButtonWithIcon := container.NewGridWithRows(2, statsIcon, statsButton)

	contactsIcon, err := getFyneImageIcon("Contacts")
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}
	contactsButton := widget.NewButton("Contacts", func(){
			setMyContactsPage(window, "Moderator", currentPage)
		})
	contactsButtonWithIcon := container.NewGridWithRows(2, contactsIcon, contactsButton)

	controversyIcon, err := getFyneImageIcon("Controversy")
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}
	controversyButton := widget.NewButton("Controversy", func(){
			//TODO: A page to tune the controversy calculation
			showUnderConstructionDialog(window)
		})
	controversyButtonWithIcon := container.NewGridWithRows(2, controversyIcon, controversyButton)

	pageButtonsRow := getContainerCentered(container.NewGridWithRows(1, filtersButtonWithIcon, statsButtonWithIcon, contactsButtonWithIcon, controversyButtonWithIcon))

	currentSortByAttribute, err := viewedModerators.GetViewedModeratorsSortByAttribute()
	if (err != nil) {
		setErrorEncounteredPage(window, err, previousPage)
		return	
	}

	sortingByLabel := getBoldLabel(translate("Sorting By:"))

	getSortByAttributeTitle := func()string{

		if (currentSortByAttribute == "IdentityScore"){
			result := translate("Identity Score")

			return result
		}
		if (currentSortByAttribute == "NumberOfReviews"){
			result := translate("Number Of Reviews")

			return result
		}

		if (currentSortByAttribute == "BanAdvocates"){
			result := translate("Ban Advocates")
			return result
		}

		result := translate(currentSortByAttribute)
		return result
	}

	sortByAttributeTitle := getSortByAttributeTitle()

	sortByAttributeButton := widget.NewButton(sortByAttributeTitle, func(){
			setSelectViewedModeratorsSortByAttributePage(window, currentPage)
		})

	getSortDirectionButtonWithIcon := func()(fyne.Widget, error){

		currentSortDirection, err := viewedModerators.GetViewedModeratorsSortDirection()
		if (err != nil){ return nil, err }

		if (currentSortDirection == "Ascending"){

			button := widget.NewButtonWithIcon(translate("Ascending"), theme.MoveUpIcon(), func(){
					appMemory.SetMemoryEntry("StopBuildViewedModeratorsYesNo", "Yes")
					_ = mySettings.SetSetting("ViewedModeratorsSortDirection", "Descending")
					_ = mySettings.SetSetting("ViewedModeratorsSortedStatus", "No")
					_ = mySettings.SetSetting("ViewedModeratorsViewIndex", "0")
					currentPage()
				})

			return button, nil
		}

		button := widget.NewButtonWithIcon(translate("Descending"), theme.MoveDownIcon(), func(){
				appMemory.SetMemoryEntry("StopBuildViewedModeratorsYesNo", "Yes")
				_ = mySettings.SetSetting("ViewedModeratorsSortDirection", "Ascending")
				_ = mySettings.SetSetting("ViewedModeratorsSortedStatus", "No")
				_ = mySettings.SetSetting("ViewedModeratorsViewIndex", "0")
				currentPage()
			})

		return button, nil
	}

	sortByDirectionButton, err := getSortDirectionButtonWithIcon()
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	sortByRow := container.NewHBox(layout.NewSpacer(), sortingByLabel, sortByAttributeButton, sortByDirectionButton, layout.NewSpacer())

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

	viewedModeratorsReady, err := viewedModerators.GetViewedModeratorsAreReadyStatus(appNetworkType)
	if (err != nil) {
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	if (viewedModeratorsReady == false){

		progressPercentageBinding := binding.NewFloat()
		sortingStatusBinding := binding.NewString()		

		startUpdateModeratorsAndProgressBarProgress := func(){

			err := viewedModerators.StartUpdatingViewedModerators(appNetworkType)
			if (err != nil) {
				fyne.Do(func(){setErrorEncounteredPage(window, err, previousPage)})
				return
			}

			sortingStatusBindingSet := false

			var encounteredError error

			for {

				pageHasChanged := checkIfPageHasChangedFunction()
				if (pageHasChanged == true){
					appMemory.SetMemoryEntry("StopBuildViewedModeratorsYesNo", "Yes")
					return
				}

				buildEncounteredError, errorEncounteredString, buildIsStopped, viewedModeratorsAreReady, currentPercentageProgress, err := viewedModerators.GetViewedModeratorsBuildStatus(appNetworkType)
				if (err != nil){
					encounteredError = err
					break
				}
				if (buildEncounteredError == true){
					encounteredError = errors.New(errorEncounteredString)
					break
				}

				if (buildIsStopped == true){
					return
				}

				if (viewedModeratorsAreReady == true){		
					progressPercentageBinding.Set(1)

					// We wait so that the loading bar will appear complete.
					time.Sleep(100 * time.Millisecond)

					fyne.Do(currentPage)
					return
				}

				progressPercentageBinding.Set(currentPercentageProgress)

				if (currentPercentageProgress >= .50 && sortingStatusBindingSet == false){

					numberOfModerators, err := viewedModerators.GetNumberOfGeneratedViewedModerators()
					if (err != nil) {
						encounteredError = err
						break
					}
					if (numberOfModerators != 0){
						numberOfModeratorsString := helpers.ConvertIntToString(numberOfModerators)
						sortingStatusBinding.Set("Sorting " + numberOfModeratorsString + " Moderators...")
					}
					sortingStatusBindingSet = true
				}

				time.Sleep(100 * time.Millisecond)
			}
			// This will only be reached if an error occurred
			errorToShow := errors.New("Error encountered while generating viewed moderators: " + encounteredError.Error())
			fyne.Do(func(){setErrorEncounteredPage(window, errorToShow, currentPage)})
		}

		loadingLabel := getBoldLabelCentered("Loading Moderators...")

		loadingBar := getWidgetCentered(widget.NewProgressBarWithData(progressPercentageBinding))

		loadingDetailsLabel := widget.NewLabelWithData(sortingStatusBinding)
		loadingDetailsLabel.TextStyle = getFyneTextStyle_Italic()
		loadingDetailsLabelCentered := getWidgetCentered(loadingDetailsLabel)

		page := container.NewVBox(title, backButton, widget.NewSeparator(), pageButtonsRow, widget.NewSeparator(), sortByRow, widget.NewSeparator(), loadingLabel, loadingBar, loadingDetailsLabelCentered)

		setPageContent(page, window)

		go startUpdateModeratorsAndProgressBarProgress()

		return
	}

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

		getRefreshResultsButtonText := func()(string, error){
			needsRefresh, err := viewedModerators.CheckIfViewedModeratorsNeedsRefresh()
			if (err != nil) { return "", err }

			if (needsRefresh == false){
				return "Refresh Results", nil	
			}
			return "Refresh Results - Updates Available!", nil
		}
		refreshButtonText, err := getRefreshResultsButtonText()
		if (err != nil){ return nil, err }

		refreshResultsButton := getWidgetCentered(widget.NewButtonWithIcon(refreshButtonText, theme.ViewRefreshIcon(), func(){
				_ = mySettings.SetSetting("ViewedModeratorsGeneratedStatus", "No")
				_ = mySettings.SetSetting("ViewedModeratorsViewIndex", "0")
				currentPage()		
			}))

		listIsReady, currentViewedModeratorsList, err := viewedModerators.GetViewedModeratorsList(appNetworkType)
		if (err != nil) { return nil, err }
		if (listIsReady == false){
			return nil, errors.New("Viewed moderators list is not ready after earlier status check determined it was.")
		}

		numberOfViewedModerators := len(currentViewedModeratorsList)

		if (numberOfViewedModerators == 0){

			noModeratorsFoundLabel := getBoldLabelCentered("No Moderators Found")

			numberOfFilters, err := viewedModerators.GetNumberOfActiveModeratorFilters()
			if (err != nil) { return nil, err }
			if (numberOfFilters == 0){
				noModeratorsFoundWithRefreshButton := container.NewVBox(noModeratorsFoundLabel, refreshResultsButton)
				return noModeratorsFoundWithRefreshButton, nil
			}

			numberOfFiltersString := helpers.ConvertIntToString(numberOfFilters)

			getActiveFiltersText := func()string{
				if (numberOfFilters == 1){
					return "active filter"
				}
				return "active filters"
			}

			activeFiltersText := getActiveFiltersText()

			activeFiltersLabel := getLabelCentered(numberOfFiltersString + " " + activeFiltersText)

			noModeratorsFoundWithFiltersInfo := container.NewVBox(noModeratorsFoundLabel, activeFiltersLabel, refreshResultsButton)

			return noModeratorsFoundWithFiltersInfo, nil
		}

		getCurrentViewIndex := func()(int, error){

			exists, viewIndexString, err := mySettings.GetSetting("ViewedModeratorsViewIndex")
			if (err != nil) { return 0, err }
			if (exists == false){
				return 0, nil
			}

			viewIndex, err := helpers.ConvertStringToInt(viewIndexString)
			if (err != nil || viewIndex < 0) {
				return 0, nil
			}

			maximumViewIndex := numberOfViewedModerators-1
			if (viewIndex > maximumViewIndex){

				return maximumViewIndex, nil
			}
			return viewIndex, nil
		}

		viewIndex, err := getCurrentViewIndex()
		if (err != nil) { return nil, err }

		getNavigateToBeginningButton := func()fyne.Widget{

			if (numberOfViewedModerators <= 5 || viewIndex == 0){

				emptyButton := widget.NewButton("  ", nil)

				return emptyButton
			}

			goToBeginningButton := widget.NewButtonWithIcon("", theme.MediaSkipPreviousIcon(), func(){
					_ = mySettings.SetSetting("ViewedModeratorsViewIndex", "0")
					currentPage()
				})

			return goToBeginningButton
		}

		getNavigateToEndButton := func()fyne.Widget{

			emptyButton := widget.NewButton("  ", nil)

			if (numberOfViewedModerators <= 5){
				return emptyButton
			}

			finalPageMinimumIndex := numberOfViewedModerators - 5

			if (viewIndex >= finalPageMinimumIndex){
				return emptyButton
			}

			goToEndButton := widget.NewButtonWithIcon("", theme.MediaSkipNextIcon(), func(){
					finalPageIndexString := helpers.ConvertIntToString(finalPageMinimumIndex)
					_ = mySettings.SetSetting("ViewedModeratorsViewIndex", finalPageIndexString)
					currentPage()
				})

			return goToEndButton
		}

		getNavigateLeftButton := func()fyne.Widget{

			if (numberOfViewedModerators <= 5 || viewIndex == 0){

				emptyButton := widget.NewButton("  ", nil)
				return emptyButton
			}

			leftButton := widget.NewButtonWithIcon("", theme.NavigateBackIcon(), func(){
					newIndex := helpers.ConvertIntToString(viewIndex-5)
					_ = mySettings.SetSetting("ViewedModeratorsViewIndex", newIndex)
					currentPage()
				})

			return leftButton
		}

		getNavigateRightButton := func()fyne.Widget{

			emptyButton := widget.NewButton("  ", nil)			

			if (numberOfViewedModerators <= 5){

				return emptyButton
			}

			finalPageMinimumIndex := numberOfViewedModerators - 5

			if (viewIndex >= finalPageMinimumIndex){
				return emptyButton
			}

			rightButton := widget.NewButtonWithIcon("", theme.NavigateNextIcon(), func(){
					newIndex := helpers.ConvertIntToString(viewIndex+5)
					_ = mySettings.SetSetting("ViewedModeratorsViewIndex", newIndex)
					currentPage()
				})

			return rightButton
		}

		getViewingModeratorsInfoRow := func()*fyne.Container{

			numberOfViewedModeratorsString := helpers.ConvertIntToString(numberOfViewedModerators)

			getModeratorOrModeratorsText := func()string{
				if (numberOfViewedModerators == 1){
					return "Moderator"
				}
				return "Moderators"
			}
			moderatorOrModeratorsText := getModeratorOrModeratorsText()

			numberOfViewedModeratorsLabel := getBoldLabel("Viewing " + numberOfViewedModeratorsString + " " + moderatorOrModeratorsText)

			if (numberOfViewedModerators <= 5){
				viewingModeratorsInfoRow := getWidgetCentered(numberOfViewedModeratorsLabel)
				return viewingModeratorsInfoRow
			}

			navigateToBeginningButton := getNavigateToBeginningButton()
			navigateToEndButton := getNavigateToEndButton()
			navigateLeftButton := getNavigateLeftButton()
			navigateRightButton := getNavigateRightButton()

			viewingModeratorsInfoRow := container.NewHBox(layout.NewSpacer(), navigateToBeginningButton, navigateLeftButton, numberOfViewedModeratorsLabel, navigateRightButton, navigateToEndButton, layout.NewSpacer())

			return viewingModeratorsInfoRow
		}

		viewingModeratorsInfoRow := getViewingModeratorsInfoRow()

		moderatorResultsContainer := container.NewVBox()

		if (viewIndex == 0){
			moderatorResultsContainer.Add(refreshResultsButton)
			moderatorResultsContainer.Add(widget.NewSeparator())
		}

		emptyLabelA := widget.NewLabel("")
		nameLabel := getItalicLabelCentered("Name")
		identityHashTitle := getItalicLabelCentered("Identity Hash")
		featuredAttributeTitle := getItalicLabelCentered(sortByAttributeTitle)
		emptyLabelB := widget.NewLabel("")

		resultIndexColumn := container.NewVBox(emptyLabelA, widget.NewSeparator())
		nameColumn := container.NewVBox(nameLabel, widget.NewSeparator())
		identityHashColumn := container.NewVBox(identityHashTitle, widget.NewSeparator())
		featuredAttributeColumn := container.NewVBox(featuredAttributeTitle, widget.NewSeparator())
		viewButtonsColumn := container.NewVBox(emptyLabelB, widget.NewSeparator())

		viewIndexOnwardsModeratorIdentityHashesList := currentViewedModeratorsList[viewIndex:]

		for index, moderatorIdentityHash := range viewIndexOnwardsModeratorIdentityHashesList{

			resultIndex := viewIndex + index + 1
			resultIndexString := helpers.ConvertIntToString(resultIndex)
	
			resultIndexBoldLabel := getBoldLabel(resultIndexString + ".")

			profileExists, _, getAnyModeratorAttributeFunction, err := viewableProfiles.GetRetrieveAnyNewestViewableUserProfileAttributeFunction(moderatorIdentityHash, appNetworkType, true, true, true)
			if (err != nil) { return nil, err }
			if (profileExists == false) {
				// Profile has been deleted since results were generated
				continue
			}

			getUserName := func()(string, error){
				exists, _, username, err := getAnyModeratorAttributeFunction("Username")				
				if (err != nil) { return "", err }
				if (exists == false) {
					return "Anonymous", nil
				}

				theirUsernameTrimmed, _, err := helpers.TrimAndFlattenString(username, 15)
				if (err != nil) { return "", err }
				return theirUsernameTrimmed, nil
			}

			currentTheirUsername, err := getUserName()
			if (err != nil) { return nil, err }

			userNameLabel := getBoldLabelCentered(currentTheirUsername)

			moderatorIdentityHashString, _, err := identity.EncodeIdentityHashBytesToString(moderatorIdentityHash)
			if (err != nil) { return nil, err }

			theirIdentityHashTrimmed, _, err := helpers.TrimAndFlattenString(moderatorIdentityHashString, 10)
			if (err != nil) { return nil, err }
			theirIdentityHashLabel := getBoldLabelCentered(theirIdentityHashTrimmed)

			getFeaturedAttributeValue := func()(string, error){

				exists, _, featuredAttributeValue, err := getAnyModeratorAttributeFunction(currentSortByAttribute)
				if (err != nil) { return "", err }
				if (exists == false){
					return "Unknown", nil
				}

				return featuredAttributeValue, nil
			}			

			featuredAttributeValue, err := getFeaturedAttributeValue()
			if (err != nil) { return nil, err }

			featuredAttributeValueLabel := getBoldLabelCentered(featuredAttributeValue)

			viewModeratorButton := widget.NewButtonWithIcon("View", theme.VisibilityIcon(), func(){
					setViewModeratorDetailsPage(window, moderatorIdentityHash, currentPage)
				})

			resultIndexColumn.Add(resultIndexBoldLabel)
			nameColumn.Add(userNameLabel)
			identityHashColumn.Add(theirIdentityHashLabel)
			featuredAttributeColumn.Add(featuredAttributeValueLabel)
			viewButtonsColumn.Add(viewModeratorButton)

			resultIndexColumn.Add(widget.NewSeparator())
			nameColumn.Add(widget.NewSeparator())
			identityHashColumn.Add(widget.NewSeparator())
			featuredAttributeColumn.Add(widget.NewSeparator())
			viewButtonsColumn.Add(widget.NewSeparator())

			if (index >= 4){
				break
			}
		}

		moderatorResultsGrid := container.NewHBox(layout.NewSpacer(), resultIndexColumn, nameColumn, identityHashColumn, featuredAttributeColumn, viewButtonsColumn, layout.NewSpacer())

		moderatorResultsContainer.Add(moderatorResultsGrid)

		viewedModeratorContainerScrollable := container.NewVScroll(moderatorResultsContainer)
		viewedModeratorContainerBoxed := getWidgetBoxed(viewedModeratorContainerScrollable)

		resultsContainer := container.NewBorder(viewingModeratorsInfoRow, nil, nil, nil, viewedModeratorContainerBoxed)

		return resultsContainer, nil
	}

	resultsContainer, err := getResultsContainer()
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	header := container.NewVBox(title, backButton, widget.NewSeparator(), pageButtonsRow, widget.NewSeparator(), sortByRow, widget.NewSeparator())

	page := container.NewBorder(header, nil, nil, nil, resultsContainer)

	setPageContent(page, window)
}


func setSelectViewedModeratorsSortByAttributePage(window fyne.Window, previousPage func()){

	appMemory.SetMemoryEntry("CurrentViewedPage", "ViewedModeratorsSortBySelect")

	title := getPageTitleCentered("Select Sort By Attribute")

	backButton := getBackButtonCentered(previousPage)

	description := getLabelCentered("Choose the attribute to sort the moderators by.")	

	getSelectButton := func(attributeTitle string, attributeName string, sortDirection string) fyne.Widget{

		button := widget.NewButton(attributeTitle, func(){
			_ = mySettings.SetSetting("ViewedModeratorsSortedStatus", "No")
			_ = mySettings.SetSetting("ViewedModeratorsSortByAttribute", attributeName)
			_ = mySettings.SetSetting("ViewedModeratorsSortDirection", sortDirection)
			_ = mySettings.SetSetting("ViewedModeratorsViewIndex", "0")

			previousPage()
		})

		return button
	}

	identityScoreButton := getSelectButton("Identity Score", "IdentityScore", "Ascending")
	banAdvocatesButton := getSelectButton("Ban Advocates", "BanAdvocates", "Descending")
	controversyButton := getSelectButton("Controversy", "Controversy", "Ascending")
	numberOfReviewsButton := getSelectButton("Number Of Reviews", "NumberOfReviews", "Descending")

	buttonsGrid := getContainerCentered(container.NewGridWithColumns(1, identityScoreButton, banAdvocatesButton, controversyButton, numberOfReviewsButton))

	content := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), buttonsGrid)

	setPageContent(content, window)
}


