package gui

// viewGeneticReferencesGui.go implements pages to display information about genetic diseases and traits

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

import "seekia/internal/genetics/geneticReferences/locusMetadata"
import "seekia/internal/genetics/geneticReferences/traits"
import "seekia/internal/genetics/geneticReferences/monogenicDiseases"
import "seekia/internal/genetics/geneticReferences/polygenicDiseases"
import "seekia/internal/helpers"

import "strings"
import "slices"
import "errors"


func setViewMonogenicDiseaseDetailsPage(window fyne.Window, diseaseName string, previousPage func()){

	currentPage := func(){setViewMonogenicDiseaseDetailsPage(window, diseaseName, previousPage)}

	title := getPageTitleCentered("Monogenic Disease Details - " + diseaseName)

	backButton := getBackButtonCentered(previousPage)

	diseaseObject, err := monogenicDiseases.GetMonogenicDiseaseObject(diseaseName)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	diseaseGeneName := diseaseObject.GeneName
	diseaseIsDominantOrRecessive := diseaseObject.DominantOrRecessive
	diseaseDescription := diseaseObject.DiseaseDescription
	diseaseReferencesMap := diseaseObject.References

	diseaseNameLabel := widget.NewLabel("Disease Name:")
	diseaseNameText := getBoldLabel(diseaseName)
	diseaseNameRow := container.NewHBox(layout.NewSpacer(), diseaseNameLabel, diseaseNameText, layout.NewSpacer())

	geneNameLabel := widget.NewLabel("Gene Name:")
	geneNameText := getBoldLabel(diseaseGeneName)
	geneNameRow := container.NewHBox(layout.NewSpacer(), geneNameLabel, geneNameText, layout.NewSpacer())

	dominantOrRecessiveLabel := widget.NewLabel("Dominant or Recessive?:")
	dominantOrRecessiveText := getBoldLabel(diseaseIsDominantOrRecessive)
	dominantOrRecessiveRow := container.NewHBox(layout.NewSpacer(), dominantOrRecessiveLabel, dominantOrRecessiveText, layout.NewSpacer())

	diseaseDescriptionTrimmed, _, err := helpers.TrimAndFlattenString(diseaseDescription, 10)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	diseaseDescriptionLabel := widget.NewLabel("Description:")
	diseaseDescriptionText := getBoldLabel(diseaseDescriptionTrimmed)
	viewDiseaseDescriptionButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
			setViewTextPage(window, "Disease Description", diseaseDescription, false, currentPage)
		})
	diseaseDescriptionRow := container.NewHBox(layout.NewSpacer(), diseaseDescriptionLabel, diseaseDescriptionText, viewDiseaseDescriptionButton, layout.NewSpacer())

	viewReferencesButton := getWidgetCentered(widget.NewButtonWithIcon("View References", theme.ListIcon(), func(){
			setViewGeneticAnalysisReferencesPage(window, "Monogenic Disease", diseaseReferencesMap, currentPage)
		}))

	page := container.NewVBox(title, backButton, widget.NewSeparator(), diseaseNameRow, widget.NewSeparator(), geneNameRow, widget.NewSeparator(), dominantOrRecessiveRow, widget.NewSeparator(), diseaseDescriptionRow, widget.NewSeparator(), viewReferencesButton)

	setPageContent(page, window)
}

func setViewMonogenicDiseaseVariantDetailsPage(window fyne.Window, diseaseName string, variantIdentifier string, previousPage func()){

	currentPage := func(){setViewMonogenicDiseaseVariantDetailsPage(window, diseaseName, variantIdentifier, previousPage)}

	title := getPageTitleCentered("Viewing Monogenic Disease Variant Details")

	backButton := getBackButtonCentered(previousPage)

	diseaseNameLabel := widget.NewLabel("Disease Name:")
	diseaseNameText := getBoldLabel(diseaseName)
	diseaseNameRow := container.NewHBox(layout.NewSpacer(), diseaseNameLabel, diseaseNameText, layout.NewSpacer())

	variantObject, err := monogenicDiseases.GetMonogenicDiseaseVariantObject(diseaseName, variantIdentifier)
	if (err != nil) {
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	variantNamesList := variantObject.VariantNames
	nucleotideChange := variantObject.NucleotideChange
	aminoAcidChange := variantObject.AminoAcidChange
	variantRSID := variantObject.VariantRSID
	variantEffectIsMild := variantObject.EffectIsMild
	referencesMap := variantObject.References

	variantRSIDsList := []int64{variantRSID}

	// We add aliases to variantRSIDsList

	anyAliasesExist, rsidAliasesList, err := locusMetadata.GetRSIDAliases(variantRSID)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}
	if (anyAliasesExist == true){
		variantRSIDsList = append(variantRSIDsList, rsidAliasesList...)
	}

	getVariantNamesLabelText := func()string{

		if(len(variantNamesList) == 1){
			return "Variant Name:"
		}
		return "Variant Names:"
	}

	variantNamesLabelText := getVariantNamesLabelText()

	variantNamesListString := strings.Join(variantNamesList, ", ")
	variantNamesLabel := widget.NewLabel(variantNamesLabelText)
	variantNamesText := getBoldLabel(variantNamesListString)
	variantNamesRow := container.NewHBox(layout.NewSpacer(), variantNamesLabel, variantNamesText, layout.NewSpacer())

	nucleotideChangeLabel := widget.NewLabel("Nucleotide Change:")
	nucleotideChangeText := getBoldLabel(nucleotideChange)
	nucleotideChangeRow := container.NewHBox(layout.NewSpacer(), nucleotideChangeLabel, nucleotideChangeText, layout.NewSpacer())
	
	page := container.NewVBox(title, backButton, widget.NewSeparator(), diseaseNameRow, widget.NewSeparator(), variantNamesRow, widget.NewSeparator(), nucleotideChangeRow, widget.NewSeparator())

	if (aminoAcidChange != ""){
		aminoAcidChangeLabel := widget.NewLabel("Amino Acid Change:")
		aminoAcidChangeText := getBoldLabel(aminoAcidChange)
		aminoAcidChangeRow := container.NewHBox(layout.NewSpacer(), aminoAcidChangeLabel, aminoAcidChangeText, layout.NewSpacer())

		page.Add(aminoAcidChangeRow)
		page.Add(widget.NewSeparator())
	}

	getVariantRSIDsLabelText := func()string{
		if (len(variantRSIDsList) == 1){
			return "Variant rsID:"
		}
		return "Variant rsIDs:"
	}

	variantRSIDsLabelText := getVariantRSIDsLabelText()

	variantRSIDStringsList := make([]string, 0, len(variantRSIDsList))

	for _, variantRSID := range variantRSIDsList{

		variantRSIDString := helpers.ConvertInt64ToString(variantRSID)

		variantRSIDName := "rs" + variantRSIDString

		variantRSIDStringsList = append(variantRSIDStringsList, variantRSIDName)
	}

	variantRSIDsListString := strings.Join(variantRSIDStringsList, ", ")
	variantRSIDsLabel := widget.NewLabel(variantRSIDsLabelText)
	variantRSIDsText := getBoldLabel(variantRSIDsListString)
	variantRSIDsRow := container.NewHBox(layout.NewSpacer(), variantRSIDsLabel, variantRSIDsText, layout.NewSpacer())
	page.Add(variantRSIDsRow)
	page.Add(widget.NewSeparator())

	effectIsMildString := helpers.ConvertBoolToYesOrNoString(variantEffectIsMild)
	effectIsMildLabel := widget.NewLabel("Effect is Mild:")
	effectIsMildText := getBoldLabel(effectIsMildString)
	effectIsMildHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
			setVariantEffectIsMildExplainerPage(window, currentPage)
		})
	effectIsMildRow := container.NewHBox(layout.NewSpacer(), effectIsMildLabel, effectIsMildText, effectIsMildHelpButton, layout.NewSpacer())
	page.Add(effectIsMildRow)
	page.Add(widget.NewSeparator())

	viewReferencesButton := getWidgetCentered(widget.NewButtonWithIcon("View References", theme.ListIcon(), func(){
			setViewGeneticAnalysisReferencesPage(window, "Variant", referencesMap, currentPage)
		}))
	page.Add(viewReferencesButton)

	setPageContent(page, window)
}

func setViewPolygenicDiseaseDetailsPage(window fyne.Window, diseaseName string, previousPage func()){

	currentPage := func(){setViewPolygenicDiseaseDetailsPage(window, diseaseName, previousPage)}

	title := getPageTitleCentered("Disease Details - " + diseaseName)

	backButton := getBackButtonCentered(previousPage)

	diseaseObject, err := polygenicDiseases.GetPolygenicDiseaseObject(diseaseName)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}	

	diseaseDescription := diseaseObject.DiseaseDescription
	effectedSex := diseaseObject.EffectedSex
	diseaseReferencesMap := diseaseObject.References

	diseaseNameLabel := widget.NewLabel("Disease Name:")
	diseaseNameText := getBoldLabel(diseaseName)
	diseaseNameRow := container.NewHBox(layout.NewSpacer(), diseaseNameLabel, diseaseNameText, layout.NewSpacer())

	getEffectedSexTextLabelText := func()string{
		if (effectedSex == "Both"){
			return "Male and Female"
		}
		return effectedSex
	}

	effectedSexTextLabelText := getEffectedSexTextLabelText()

	effectedSexLabel := widget.NewLabel("Effected Sex:")
	effectedSexText := getBoldLabel(effectedSexTextLabelText)
	effectedSexRow := container.NewHBox(layout.NewSpacer(), effectedSexLabel, effectedSexText, layout.NewSpacer())

	diseaseDescriptionTrimmed, _, err := helpers.TrimAndFlattenString(diseaseDescription, 10)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	diseaseDescriptionLabel := widget.NewLabel("Description:")
	diseaseDescriptionText := getBoldLabel(diseaseDescriptionTrimmed)
	viewDiseaseDescriptionButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
			setViewTextPage(window, "Disease Description", diseaseDescription, false, currentPage)
		})
	diseaseDescriptionRow := container.NewHBox(layout.NewSpacer(), diseaseDescriptionLabel, diseaseDescriptionText, viewDiseaseDescriptionButton, layout.NewSpacer())

	viewReferencesButton := getWidgetCentered(widget.NewButtonWithIcon("View References", theme.ListIcon(), func(){
			setViewGeneticAnalysisReferencesPage(window, "Polygenic Disease", diseaseReferencesMap, currentPage)
		}))

	page := container.NewVBox(title, backButton, widget.NewSeparator(), diseaseNameRow, widget.NewSeparator(), effectedSexRow, widget.NewSeparator(), diseaseDescriptionRow, widget.NewSeparator(), viewReferencesButton)

	setPageContent(page, window)
}


func setViewGeneticAnalysisReferencesPage(window fyne.Window, referencesTopic string, referencesMap map[string]string, previousPage func()){

	currentPage := func(){setViewGeneticAnalysisReferencesPage(window, referencesTopic, referencesMap, previousPage)}

	pageTitle := "Viewing " + referencesTopic + " References"

	title := getPageTitleCentered(pageTitle)

	backButton := getBackButtonCentered(previousPage)

	referencesContainer := container.NewVBox()

	referenceNamesList := helpers.GetListOfMapKeys(referencesMap)

	// We sort the references so they always show up in the same order
	slices.Sort(referenceNamesList)

	for index, referenceName := range referenceNamesList{

		referenceLink, exists := referencesMap[referenceName]
		if (exists == false){
			setErrorEncounteredPage(window, errors.New("referencesMap missing referenceName"), previousPage)
			return
		}

		indexString := helpers.ConvertIntToString(index+1)

		indexLabel := getBoldLabel(indexString + ".")

		referenceNameTrimmed, _, err := helpers.TrimAndFlattenString(referenceName, 35)
		if (err != nil) {
			setErrorEncounteredPage(window, err, previousPage)
			return
		}
		referenceNameLabel := getItalicLabel(referenceNameTrimmed)

		referenceViewNameButton := widget.NewButtonWithIcon("View Name", theme.VisibilityIcon(), func(){
				setViewTextPage(window, "Viewing Reference Name", referenceName, false, currentPage)
			})

		referenceLinkButton := widget.NewButtonWithIcon("View Link", theme.VisibilityIcon(), func(){
				setViewLinkPage(window, "Viewing Reference Link", referenceLink, currentPage)
			})

		referenceRow := container.NewHBox(layout.NewSpacer(), indexLabel, referenceNameLabel, referenceViewNameButton, referenceLinkButton, layout.NewSpacer())

		referencesContainer.Add(referenceRow)
		referencesContainer.Add(widget.NewSeparator())
	}

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

	setPageContent(page, window)
}


func setViewTraitDetailsPage(window fyne.Window, traitName string, previousPage func()){

	currentPage := func(){setViewTraitDetailsPage(window, traitName, previousPage)}

	title := getPageTitleCentered("Trait Details - " + traitName)

	backButton := getBackButtonCentered(previousPage)

	traitObject, err := traits.GetTraitObject(traitName)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	traitDescription := traitObject.TraitDescription
	traitReferencesMap := traitObject.ReferencesMap

	traitNameLabel := widget.NewLabel("Trait Name:")
	traitNameText := getBoldLabel(traitName)
	traitNameRow := container.NewHBox(layout.NewSpacer(), traitNameLabel, traitNameText, layout.NewSpacer())

	traitDescriptionTrimmed, _, err := helpers.TrimAndFlattenString(traitDescription, 10)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	traitDescriptionLabel := widget.NewLabel("Description:")
	traitDescriptionText := getBoldLabel(traitDescriptionTrimmed)
	viewTraitDescriptionButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
			setViewTextPage(window, "Trait Description", traitDescription, false, currentPage)
		})
	traitDescriptionRow := container.NewHBox(layout.NewSpacer(), traitDescriptionLabel, traitDescriptionText, viewTraitDescriptionButton, layout.NewSpacer())

	viewReferencesButton := getWidgetCentered(widget.NewButtonWithIcon("View References", theme.ListIcon(), func(){
			setViewGeneticAnalysisReferencesPage(window, "Trait", traitReferencesMap, currentPage)
		}))

	page := container.NewVBox(title, backButton, widget.NewSeparator(), traitNameRow, widget.NewSeparator(), traitDescriptionRow, widget.NewSeparator(), viewReferencesButton)

	setPageContent(page, window)
}

func setViewDiscreteTraitRuleDetailsPage(window fyne.Window, traitName string, ruleIdentifier string, previousPage func()){

	currentPage := func(){setViewDiscreteTraitRuleDetailsPage(window, traitName, ruleIdentifier, previousPage)}

	title := getPageTitleCentered("Viewing Rule Details")
	
	backButton := getBackButtonCentered(previousPage)

	traitNameLabel := widget.NewLabel("Trait Name:")
	traitNameText := getBoldLabel(traitName)
	traitNameRow := container.NewHBox(layout.NewSpacer(), traitNameLabel, traitNameText, layout.NewSpacer())

	ruleIdentifierLabel := widget.NewLabel("Rule Identifier:")
	ruleIdentifierText := getBoldLabel(ruleIdentifier)
	ruleIdentifierRow := container.NewHBox(layout.NewSpacer(), ruleIdentifierLabel, ruleIdentifierText, layout.NewSpacer())

	traitRuleObject, err := traits.GetTraitRuleObject(traitName, ruleIdentifier)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	ruleOutcomePointsMap := traitRuleObject.OutcomePointsMap
	ruleReferencesMap := traitRuleObject.ReferencesMap

	viewReferencesButton := getWidgetCentered(widget.NewButtonWithIcon("View References", theme.ListIcon(), func(){
			setViewGeneticAnalysisReferencesPage(window, "Rule", ruleReferencesMap, currentPage)
		}))

	ruleEffectsLabel := getBoldLabelCentered("Rule Effects:")

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

		outcomeNameLabel := getItalicLabelCentered("Outcome Name")
		outcomeEffectLabel := getItalicLabelCentered("Outcome Effect")

		outcomeNameColumn := container.NewVBox(outcomeNameLabel, widget.NewSeparator())
		outcomeEffectColumn := container.NewVBox(outcomeEffectLabel, widget.NewSeparator())

		for outcomeName, outcomePointsEffect := range ruleOutcomePointsMap{

			outcomeNameLabel := getBoldLabelCentered(outcomeName)

			getOutcomeEffect := func()string{
			
				outcomePointsEffectString := helpers.ConvertIntToString(outcomePointsEffect)

				if (outcomePointsEffect < 0){
					return outcomePointsEffectString
				}

				outcomeEffect := "+" + outcomePointsEffectString
				return outcomeEffect
			}

			outcomeEffect := getOutcomeEffect()

			outcomeEffectLabel := getBoldLabelCentered(outcomeEffect)

			outcomeNameColumn.Add(outcomeNameLabel)
			outcomeEffectColumn.Add(outcomeEffectLabel)

			outcomeNameColumn.Add(widget.NewSeparator())
			outcomeEffectColumn.Add(widget.NewSeparator())
		}

		outcomeEffectHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
				setDiscreteTraitRuleOutcomeEffectsExplainerPage(window, currentPage)
			})
		outcomeEffectColumn.Add(outcomeEffectHelpButton)

		ruleEffectsGrid := container.NewHBox(layout.NewSpacer(), outcomeNameColumn, outcomeEffectColumn, layout.NewSpacer())

		return ruleEffectsGrid, nil
	}

	ruleEffectsGrid, err := getRuleEffectsGrid()
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	page := container.NewVBox(title, backButton, widget.NewSeparator(), traitNameRow, widget.NewSeparator(), ruleIdentifierRow, widget.NewSeparator(), viewReferencesButton, widget.NewSeparator(), ruleEffectsLabel, ruleEffectsGrid)

	setPageContent(page, window)
}



