package traits

import "seekia/internal/globalSettings"
import "seekia/internal/helpers"

import "maps"

import _ "embed"

import "errors"
import "encoding/gob"
import "bytes"


//go:embed rsIDs/GiantHeightStudyLoci.gob
var GiantHeightStudyLociFile []byte


func getHeightTraitObject()(Trait, error){

	// Map Structure: rsID -> References Map
	locusReferencesMap := make(map[int64]map[string]string)

	referencesMap_List1 := make(map[string]string)
	referencesMap_List1["GIANT consortium - Meta-analyses of Genome-Wide Association Studies - 2022 - Height"] = "https://portals.broadinstitute.org/collaboration/giant/index.php/GIANT_consortium_data_files"

	// These SNPs are taken from the meta-analyses of Genome-Wide Association Studies (GWAS) created by the GIANT consortium
	//https://portals.broadinstitute.org/collaboration/giant/index.php/GIANT_consortium_data_files

	// Download link:
	// https://portals.broadinstitute.org/collaboration/giant/images/4/4e/GIANT_HEIGHT_YENGO_2022_GWAS_SUMMARY_STATS_ALL.gz

	//SHA-256 Checksum:
	// db18859724675f2f9ba86eff28cb4dacac0629c0b25c9806a6cf2eed6bb8b71e

	// See /utilities/extractGiantLoci/extractGiantLoci.go to see how they were extracted from the file

	buffer := bytes.NewBuffer(GiantHeightStudyLociFile)
	decoder := gob.NewDecoder(buffer)

	var lociList_1 []int64

	err := decoder.Decode(&lociList_1)
	if (err != nil){ return Trait{}, err }

	for _, rsID := range lociList_1{
		locusReferencesMap[rsID] = maps.Clone(referencesMap_List1)
	}

	heightLociList := helpers.GetListOfMapKeys(locusReferencesMap)

	referencesMap := make(map[string]string)
	referencesMap["GIANT consortium - Meta-analyses of Genome-Wide Association Studies - 2022 - Height"] = "https://portals.broadinstitute.org/collaboration/giant/index.php/GIANT_consortium_data_files"

	numericValueFormatter := func(inputHeight float64, _ bool)(string, error){

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

			exists, metricOrImperial, err := globalSettings.GetSetting("MetricOrImperial")
			if (err != nil) { return "", err }
			if (exists == false){
				return "Metric", nil
			}
			if (metricOrImperial != "Metric" && metricOrImperial != "Imperial"){
				return "", errors.New("Malformed globalSettings: Invalid metricOrImperial: " + metricOrImperial)
			}

			return metricOrImperial, nil
		}

		myMetricOrImperial, err := getMyMetricOrImperial()
		if (err != nil){ return "", err }
		if (myMetricOrImperial == "Metric"){
			centimetersString := helpers.ConvertFloat64ToStringRounded(inputHeight, 1)

			//TODO: Translate units

			centimetersWithUnits := centimetersString + " centimeters"

			return centimetersWithUnits, nil
		}

		feetInchesString, err := helpers.ConvertCentimetersToFeetInchesTranslatedString(inputHeight)
		if (err != nil) { return "", err }

		return feetInchesString, nil
	}

	heightObject := Trait{
		TraitName: "Height",
		TraitDescription: "The distance between the top of a standing person head and the floor.",
		DiscreteOrNumeric: "Numeric",
		LocusReferencesMap: locusReferencesMap,
		LociList: heightLociList,
		LociList_Rules: []int64{},
		RulesList: []TraitRule{},
		OutcomesList: []string{},
		NumericValueFormatter: numericValueFormatter,
		ReferencesMap: referencesMap,
	}

	return heightObject, nil
}

