package gui

// viewContentGui.go implements a page used by moderators to browse content

import "fyne.io/fyne/v2"
import "fyne.io/fyne/v2/container"
import "fyne.io/fyne/v2/widget"
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/encoding"
import "seekia/internal/helpers"
import "seekia/internal/moderation/contentControversy"
import "seekia/internal/moderation/reviewStorage"
import "seekia/internal/moderation/viewedContent"
import "seekia/internal/mySettings"
import "seekia/internal/network/appNetworkType/getAppNetworkType"

import "time"
import "errors"

// The viewedContent page provides a way for moderators to view, filter and sort all stored content
// One use of this is to sort content by controversy, to find moderators to ban

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

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

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

	//TODO: Check if moderator/host mode is enabled
	//	If not, we cannot calculate many of the attributes
	//	We should let the user know that somehow

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

	title := getPageTitleCentered("Browse Content")
	
	backButton := getBackButtonCentered(previousPage)

	statsIcon, err := getFyneImageIcon("Stats")
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}
	statsButton := widget.NewButton("Stats", func(){
			//TODO: A page to view statistics about all stored content
			showUnderConstructionDialog(window)
		})
	statsButtonWithIcon := container.NewGridWithRows(2, statsIcon, statsButton)

	filtersIcon, err := getFyneImageIcon("Desires")
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}
	filtersButton := widget.NewButton("Filters", func(){
			//TODO: A page to configure filters for the viewed content
			// Examples:
			//	-Only show content created between a certain time frame
			// 	-Only show content authored by certain identity types
			//	-Only show a certain contentType (Profile/Message)
			showUnderConstructionDialog(window)
		})
	filtersButtonWithIcon := container.NewGridWithRows(2, filtersIcon, filtersButton)

	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 parameters
			showUnderConstructionDialog(window)
		})
	controversyButtonWithIcon := container.NewGridWithRows(2, controversyIcon, controversyButton)

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

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

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

	getSortByAttributeTitle := func()string{

		if (currentSortByAttribute == "BanAdvocates"){
			result := translate("Ban Advocates")
			return result
		}
		if (currentSortByAttribute == "NumberOfReviewers"){
			result := translate("Number Of Reviewers")
			return result
		}

		result := translate(currentSortByAttribute)

		return result
	}

	sortByAttributeTitle := getSortByAttributeTitle()

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

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

		currentSortDirection, err := viewedContent.GetViewedContentSortDirection()
		if (err != nil) { return nil, err }

		if (currentSortDirection == "Ascending"){
			button := widget.NewButtonWithIcon(translate("Ascending"), theme.MoveUpIcon(), func(){
				appMemory.SetMemoryEntry("StopBuildViewedContentYesNo", "Yes")
				_ = mySettings.SetSetting("ViewedContentSortDirection", "Descending")
				_ = mySettings.SetSetting("ViewedContentSortedStatus", "No")
				_ = mySettings.SetSetting("ViewedContentViewIndex", "0")
				currentPage()
			})
			return button, nil
		}

		button := widget.NewButtonWithIcon(translate("Descending"), theme.MoveDownIcon(), func(){
			appMemory.SetMemoryEntry("StopBuildViewedContentYesNo", "Yes")
			_ = mySettings.SetSetting("ViewedContentSortDirection", "Ascending")
			_ = mySettings.SetSetting("ViewedContentSortedStatus", "No")
			_ = mySettings.SetSetting("ViewedContentViewIndex", "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
	}

	viewedContentReady, err := viewedContent.GetViewedContentIsReadyStatus(appNetworkType)
	if (err != nil) {
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	if (viewedContentReady == false){

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

		startUpdateViewedContentAndLoadingBarFunction := func(){

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

			sortingDetailsBindingSet := false

			var encounteredError error

			for{

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

				buildEncounteredError, errorEncounteredString, buildIsStopped, contentIsReady, currentPercentageProgress, err := viewedContent.GetViewedContentBuildStatus(appNetworkType)
				if (err != nil){
					encounteredError = err
					break
				}

				if (buildEncounteredError == true){
					encounteredError = errors.New(errorEncounteredString)
					break
				}

				if (buildIsStopped == true){
					return
				}

				if (contentIsReady == 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 && sortingDetailsBindingSet == false){

					numberOfContents, err := viewedContent.GetNumberOfGeneratedViewedContents()
					if (err != nil) {
						encounteredError = err
						break
					}
					if (numberOfContents != 0){

						numberOfContentsString := helpers.ConvertIntToString(numberOfContents)
						sortingDetailsBinding.Set("Sorting " + numberOfContentsString + " Contents...")
					}

					sortingDetailsBindingSet = true
				}

				time.Sleep(100 * time.Millisecond)
			}

			// This is only reached if an error is encountered during build

			errorToShow := errors.New("Error encountered during build of viewed content: " + encounteredError.Error())

			fyne.Do(func(){setErrorEncounteredPage(window, errorToShow, previousPage)})
		}

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

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

		loadingDetailsLabel := widget.NewLabelWithData(sortingDetailsBinding)
		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 startUpdateViewedContentAndLoadingBarFunction()

		return
	}

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

		getRefreshResultsButtonText := func()(string, error){
			needsRefresh, err := viewedContent.CheckIfViewedContentNeedsRefresh()
			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("ViewedContentGeneratedStatus", "No")
				_ = mySettings.SetSetting("ViewedContentViewIndex", "0")
				currentPage()		
			}))

		viewedContentIsReady, currentViewedContentList, err := viewedContent.GetViewedContentList(appNetworkType)
		if (err != nil) { return nil, err }
		if (viewedContentIsReady == false){
			return nil, errors.New("Viewed content is not ready after earlier check determined it was ready.")
		}

		numberOfViewedContents := len(currentViewedContentList)

		if (numberOfViewedContents == 0){
			
			noContentFoundLabel := getBoldLabelCentered("No content found.")
		
			numberOfFilters, err := viewedContent.GetNumberOfActiveViewedContentFilters()
			if (err != nil) { return nil, err }
			if (numberOfFilters == 0){
				noContentFoundWithRefreshButton := container.NewVBox(noContentFoundLabel, refreshResultsButton)
				return noContentFoundWithRefreshButton, nil
			}
		
			numberOfFiltersString := helpers.ConvertIntToString(numberOfFilters)

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

			activeFiltersText := getActiveFiltersText()

			activeFiltersLabel := getLabelCentered(numberOfFiltersString + " " + activeFiltersText)
		
			noContentFoundWithFiltersInfo := container.NewVBox(noContentFoundLabel, activeFiltersLabel, refreshResultsButton)

			return noContentFoundWithFiltersInfo, nil
		}

		getCurrentViewIndex := func()(int, error){
			exists, viewIndexString, err := mySettings.GetSetting("ViewedContentViewIndex")
			if (err != nil) { return 0, err }
			if (exists == false){
				return 0, nil
			}

			viewIndex, err := helpers.ConvertStringToInt(viewIndexString)
			if (err != nil){
				return 0, errors.New("MySettings invalid: Invalid ViewedContentViewIndex: " + viewIndexString)
			}
			if (viewIndex < 0) {
				return 0, nil
			}

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

				return maximumViewIndex, nil
			}
			return viewIndex, nil
		}

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

		getNavigateToBeginningButton := func()fyne.Widget{
			
			if (numberOfViewedContents <= 5 || viewIndex == 0){
	
				emptyButton := widget.NewButton("  ", nil)
				
				return emptyButton
			}

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

		getNavigateToEndButton := func()fyne.Widget{

			emptyButton := widget.NewButton("  ", nil)
			
			if (numberOfViewedContents <= 5){
				return emptyButton
			}

			finalPageMinimumIndex := numberOfViewedContents - 5

			if (viewIndex >= finalPageMinimumIndex){
				return emptyButton
			}

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

		getNavigateLeftButton := func()fyne.Widget{
			
			if (numberOfViewedContents <= 5 || viewIndex == 0){

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

			return leftButton
		}

		getNavigateRightButton := func()fyne.Widget{

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

			if (numberOfViewedContents <= 5){
				
				return emptyButton
			}

			finalPageMinimumIndex := numberOfViewedContents - 5

			if (viewIndex >= finalPageMinimumIndex){
				return emptyButton
			}

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

			return rightButton
		}

		getViewedContentInfoRow := func()*fyne.Container{

			numberOfViewedContentsString := helpers.ConvertIntToString(numberOfViewedContents)

			getResultOrResultsText := func()string{
				if (numberOfViewedContents == 1){
					return "Result"
				}
				return "Results"
			}
			
			resultOrResultsText := getResultOrResultsText()

			numberOfViewedContentsLabel := getBoldLabel("Viewing " + numberOfViewedContentsString + " " + resultOrResultsText)

			if (numberOfViewedContents <= 5){
				viewedContentInfoRow := getWidgetCentered(numberOfViewedContentsLabel)
				return viewedContentInfoRow
			}

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

			viewedContentInfoRow := container.NewHBox(layout.NewSpacer(), navigateToBeginningButton, navigateLeftButton, numberOfViewedContentsLabel, navigateRightButton, navigateToEndButton, layout.NewSpacer())

			return viewedContentInfoRow
		}

		viewedContentInfoRow := getViewedContentInfoRow()

		viewIndexOnwardsViewedContentList := currentViewedContentList[viewIndex:]

		contentResultsContainer := container.NewVBox()

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

		emptyLabel1 := widget.NewLabel("")
		contentHashTitle := getItalicLabelCentered("Content Hash")
		contentTypeTitle := getItalicLabelCentered("Content Type")
		featuredAttributeTitle := getItalicLabelCentered(sortByAttributeTitle)
		emptyLabel2 := widget.NewLabel("")

		contentIndexColumn := container.NewVBox(emptyLabel1, widget.NewSeparator())
		contentHashColumn := container.NewVBox(contentHashTitle, widget.NewSeparator())
		contentTypeColumn := container.NewVBox(contentTypeTitle, widget.NewSeparator())
		featuredAttributeColumn := container.NewVBox(featuredAttributeTitle, widget.NewSeparator())
		viewContentButtonsColumn := container.NewVBox(emptyLabel2, widget.NewSeparator())

		for index, contentHashString := range viewIndexOnwardsViewedContentList{

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

			resultIndexLabel := getBoldLabelCentered(resultIndexString + ".")

			contentHash, err := encoding.DecodeHexStringToBytes(contentHashString)
			if (err != nil){
				return nil, errors.New("Viewed content list contains invalid contentHash: " + contentHashString)
			}

			contentType, err := helpers.GetContentTypeFromContentHash(contentHash)
			if (err != nil) { return nil, err }
			if (contentType != "Profile" && contentType != "Message"){
				return nil, errors.New("Viewed content list contains invalid contentHash: " + contentHashString)
			}

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

				unknownTranslated := translate("Unknown")

				if (currentSortByAttribute == "Controversy"){

					controversyIsKnown, controversyRating, err := contentControversy.GetContentControversyRating(contentHash)
					if (err != nil) { return "", err }
					if (controversyIsKnown == false){
						return unknownTranslated, nil
					}

					controversyRatingString := helpers.ConvertInt64ToString(controversyRating)
					return controversyRatingString, nil
				}
				if (currentSortByAttribute == "NumberOfReviewers"){

					if (contentType == "Profile"){

						if (len(contentHash) != 28){
							return "", errors.New("GetContentTypeFromContentHash returning Profile for different length content hash.")
						}

						profileHash := [28]byte(contentHash)

						profileMetadataIsKnown, downloadingRequiredData, numberOfReviewers, err := reviewStorage.GetNumberOfProfileReviewers(profileHash)
						if (err != nil) { return "", err }
						if (profileMetadataIsKnown == false || downloadingRequiredData == false){
							return unknownTranslated, nil
						}

						numberOfReviewersString := helpers.ConvertIntToString(numberOfReviewers)

						return numberOfReviewersString, nil

					}
					// contentType == "Message"

					if (len(contentHash) != 26){
						return "", errors.New("GetContentTypeFromContentHash returning Message for different length content hash.")
					}

					messageHash := [26]byte(contentHash)

					messageMetadataIsKnown, downloadingRequiredData, numberOfReviewers, err := reviewStorage.GetNumberOfMessageReviewers(messageHash)
					if (err != nil) { return "", err }
					if (messageMetadataIsKnown == false || downloadingRequiredData == false){
						return unknownTranslated, nil
					}

					numberOfReviewersString := helpers.ConvertIntToString(numberOfReviewers)
					return numberOfReviewersString, nil
				}

				return "", errors.New("Unknown featured attribute: " + currentSortByAttribute)
			}

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

			featuredAttributeLabel := getBoldLabelCentered(featuredAttributeValue)

			contentTypeLabel := getBoldLabelCentered(translate(contentType))

			contentHashTrimmed, _, err := helpers.TrimAndFlattenString(contentHashString, 7)
			if (err != nil) { return nil, err }
			contentHashLabel := getBoldLabelCentered(contentHashTrimmed)

			viewContentButton := widget.NewButtonWithIcon("View Details", theme.VisibilityIcon(), func(){
					if (contentType == "Message"){

						if (len(contentHash) != 26){
							setErrorEncounteredPage(window, errors.New("GetContentTypeFromContentHash returning Message for different length content hash."), currentPage)
							return
						}

						messageHash := [26]byte(contentHash)

						setViewMessageModerationDetailsPage(window, messageHash, currentPage)

					} else if (contentType == "Profile"){

						if (len(contentHash) != 28){
							setErrorEncounteredPage(window, errors.New("GetContentTypeFromContentHash returning Profile for different length content hash."), currentPage)
							return
						}

						profileHash := [28]byte(contentHash)

						setViewProfileModerationDetailsPage(window, profileHash, currentPage)
					}
				})

			contentIndexColumn.Add(resultIndexLabel)
			contentHashColumn.Add(contentHashLabel)
			contentTypeColumn.Add(contentTypeLabel)
			featuredAttributeColumn.Add(featuredAttributeLabel)
			viewContentButtonsColumn.Add(viewContentButton)

			contentIndexColumn.Add(widget.NewSeparator())
			contentHashColumn.Add(widget.NewSeparator())
			contentTypeColumn.Add(widget.NewSeparator())
			featuredAttributeColumn.Add(widget.NewSeparator())
			viewContentButtonsColumn.Add(widget.NewSeparator())

			if (index >= 4){
				break
			}
		}

		gridInfoRowWithSeparator := container.NewVBox(viewedContentInfoRow, widget.NewSeparator())

		resultsGrid := container.NewHBox(layout.NewSpacer(), contentIndexColumn, contentHashColumn, contentTypeColumn, featuredAttributeColumn, viewContentButtonsColumn, layout.NewSpacer())

		contentResultsContainer.Add(resultsGrid)

		viewedContentContainerScrollable := container.NewVScroll(contentResultsContainer)

		resultsContainer := container.NewBorder(gridInfoRowWithSeparator, nil, nil, nil, viewedContentContainerScrollable)

		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 setSelectViewedContentSortByAttributePage(window fyne.Window, previousPage func()){
	
	appMemory.SetMemoryEntry("CurrentViewedPage", "ViewedContentSortBySelect")
	
	title := getPageTitleCentered("Select Sort By Attribute")

	backButton := getBackButtonCentered(previousPage)

	description := getLabelCentered("Select the attribute to sort the viewed content by.")

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

		button := widget.NewButton(attributeTitle, func(){
				_ = mySettings.SetSetting("ViewedContentSortedStatus", "No")
				_ = mySettings.SetSetting("ViewedContentSortByAttribute", attributeName)
				_ = mySettings.SetSetting("ViewedContentSortDirection", sortDirection)
				_ = mySettings.SetSetting("ViewedContentViewIndex", "0")

				previousPage()
			})

		return button
	}

	//TODO: Add more attributes

	controversyButton := getSelectButton("Controversy", "Controversy", "Ascending")
	numberOfReviewersButton := getSelectButton("Number Of Reviewers", "NumberOfReviewers", "Descending")
	
	buttonsGrid := getContainerCentered(container.NewGridWithColumns(1, controversyButton, numberOfReviewersButton))
	
	content := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), buttonsGrid)
	
	setPageContent(content, window)
}



