package companyAnalysis_test

import "seekia/internal/genetics/companyAnalysis"

import "seekia/internal/helpers"

import "testing"
import "strings"
import "errors"

func TestAncestralLocations_23andMe(t *testing.T){

	allAncestryLocationsList, err := companyAnalysis.GetAllAncestryLocationsList_23andMe()
	if (err != nil){
		t.Fatal("Failed to get all 23andMe ancestry locations list: " + err.Error())
	}

	containsDuplicates, duplicateLocationName := helpers.CheckIfListContainsDuplicates(allAncestryLocationsList)
	if (containsDuplicates == true){
		t.Fatal("allAncestryLocationsList contains duplicate locationName: " + duplicateLocationName)
	}

	for _, locationName := range allAncestryLocationsList{

		containsAny := strings.ContainsAny(locationName, "$+#")
		if (containsAny == true){
			t.Fatal("allAncestryLocationsList contains invalid location: " + locationName)
		}
	}

	ancestryContinentsList := companyAnalysis.GetAncestryContinentsList_23andMe()

	for _, continentName := range ancestryContinentsList{

		regionsList, err := companyAnalysis.GetAncestryContinentRegionsList_23andMe(continentName)
		if (err != nil){
			t.Fatal("GetAncestryContinentRegionsList_23andMe failed: " + err.Error())
		}

		for _, regionName := range regionsList{

			parentContinentName, err := companyAnalysis.GetAncestryRegionParentContinent_23andMe(regionName)
			if (err != nil){
				t.Fatal("GetAncestryRegionContinent_23andMe failed: " + err.Error())
			}

			if (parentContinentName != continentName){
				t.Fatal("GetAncestryRegionParentContinent_23andMe returning invalid parent continent for region: " + regionName + ". Output: " + parentContinentName)
			}

			subregionsList, err := companyAnalysis.GetAncestryRegionSubregionsList_23andMe(continentName, regionName)
			if (err != nil){
				t.Fatal("GetAncestryRegionSubregionsList_23andMe failed: " + err.Error())
			}

			for _, subregionName := range subregionsList{

				parentRegionName, err := companyAnalysis.GetAncestrySubregionParentRegion_23andMe(subregionName)
				if (err != nil){
					t.Fatal("GetAncestryRegionContinent_23andMe failed: " + err.Error())
				}
				if (parentRegionName != regionName){
					t.Fatal("GetAncestrySubregionParentRegion_23andMe returning invalid parent region for subregion: " + subregionName + ". Output: " + parentRegionName)
				}

			}
		}
	}

	// TODO: Create a composition using all locations to learn the maximum size of this attribute
}


func TestAncestralSimilarity_23andMe(t *testing.T){

	testAncestralSimilarity := func(person1ContinentsMap map[string]float64, person1RegionsMap map[string]float64, person1SubregionsMap map[string]float64, person2ContinentsMap map[string]float64, person2RegionsMap map[string]float64, person2SubregionsMap map[string]float64, expectedAncestralSimilarity int)error{

		inputsAreValid, person1AncestryCompositionAttribute, err := companyAnalysis.CreateAncestryCompositionAttribute_23andMe(person1ContinentsMap, person1RegionsMap, person1SubregionsMap)
		if (err != nil){ return err }
		if (inputsAreValid == false){
			return errors.New("testAncestralSimilarity called with invalid person1 location maps.")
		}

		inputsAreValid, person2AncestryCompositionAttribute, err := companyAnalysis.CreateAncestryCompositionAttribute_23andMe(person2ContinentsMap, person2RegionsMap, person2SubregionsMap)
		if (err != nil){ return err }
		if (inputsAreValid == false){
			return errors.New("testAncestralSimilarity called with invalid person2 location maps.")
		}

		ancestralSimilarity, err := companyAnalysis.GetAncestralSimilarity_23andMe(true, person1AncestryCompositionAttribute, person2AncestryCompositionAttribute)
		if (err != nil) { return err }

		if (ancestralSimilarity != expectedAncestralSimilarity){
			ancestralSimilarityString := helpers.ConvertIntToString(ancestralSimilarity)
			expectedAncestralSimilarityString := helpers.ConvertIntToString(expectedAncestralSimilarity)
			return errors.New("testAncestralSimilarity returning unexpected ancestral similarity: " + ancestralSimilarityString + " != " + expectedAncestralSimilarityString)
		}

		return nil
	}

	{
		person1ContinentsMap := map[string]float64{
			"Unassigned": 100,
		}
		person1RegionsMap := map[string]float64{}
		person1SubregionsMap := map[string]float64{}

		person2ContinentsMap := map[string]float64{
			"Melanesian": 100,
		}
		person2RegionsMap := map[string]float64{}
		person2SubregionsMap := map[string]float64{}

		err := testAncestralSimilarity(person1ContinentsMap, person1RegionsMap, person1SubregionsMap, person2ContinentsMap, person2RegionsMap, person2SubregionsMap, 0)
		if (err != nil){
			t.Fatal("testAncestralSimilarity failed test 1: " + err.Error())
		}
	}

	{
		person1ContinentsMap := map[string]float64{
			"Melanesian": 100,
		}
		person1RegionsMap := map[string]float64{}
		person1SubregionsMap := map[string]float64{}

		person2ContinentsMap := map[string]float64{
			"Melanesian": 100,
		}
		person2RegionsMap := map[string]float64{}
		person2SubregionsMap := map[string]float64{}

		err := testAncestralSimilarity(person1ContinentsMap, person1RegionsMap, person1SubregionsMap, person2ContinentsMap, person2RegionsMap, person2SubregionsMap, 100)
		if (err != nil){
			t.Fatal("testAncestralSimilarity failed test 2: " + err.Error())
		}
	}

	{
		person1ContinentsMap := map[string]float64{
			"Melanesian": 50,
			"Unassigned": 50,
		}
		person1RegionsMap := map[string]float64{}
		person1SubregionsMap := map[string]float64{}

		person2ContinentsMap := map[string]float64{
			"Melanesian": 50,
			"Unassigned": 50,
		}
		person2RegionsMap := map[string]float64{}
		person2SubregionsMap := map[string]float64{}

		err := testAncestralSimilarity(person1ContinentsMap, person1RegionsMap, person1SubregionsMap, person2ContinentsMap, person2RegionsMap, person2SubregionsMap, 100)
		if (err != nil){
			t.Fatal("testAncestralSimilarity failed test 3: " + err.Error())
		}
	}

	{
		person1ContinentsMap := map[string]float64{
			"Melanesian": 100,
		}
		person1RegionsMap := map[string]float64{}
		person1SubregionsMap := map[string]float64{}

		person2ContinentsMap := map[string]float64{
			"Melanesian": 50,
			"Unassigned": 50,
		}
		person2RegionsMap := map[string]float64{}
		person2SubregionsMap := map[string]float64{}

		err := testAncestralSimilarity(person1ContinentsMap, person1RegionsMap, person1SubregionsMap, person2ContinentsMap, person2RegionsMap, person2SubregionsMap, 50)
		if (err != nil){
			t.Fatal("testAncestralSimilarity failed test 4: " + err.Error())
		}
	}

	{
		person1ContinentsMap := map[string]float64{}
		person1RegionsMap := map[string]float64{}
		person1SubregionsMap := map[string]float64{
			"Siberian": 100,
		}

		person2ContinentsMap := map[string]float64{}
		person2RegionsMap := map[string]float64{}
		person2SubregionsMap := map[string]float64{
			"Siberian": 100,
		}

		err := testAncestralSimilarity(person1ContinentsMap, person1RegionsMap, person1SubregionsMap, person2ContinentsMap, person2RegionsMap, person2SubregionsMap, 100)
		if (err != nil){
			t.Fatal("testAncestralSimilarity failed test 5: " + err.Error())
		}
	}

	{
		person1ContinentsMap := map[string]float64{}
		person1RegionsMap := map[string]float64{}
		person1SubregionsMap := map[string]float64{
			"Siberian": 100,
		}

		person2ContinentsMap := map[string]float64{}
		person2RegionsMap := map[string]float64{}
		person2SubregionsMap := map[string]float64{
			"Siberian": 100,
		}

		err := testAncestralSimilarity(person1ContinentsMap, person1RegionsMap, person1SubregionsMap, person2ContinentsMap, person2RegionsMap, person2SubregionsMap, 100)
		if (err != nil){
			t.Fatal("testAncestralSimilarity failed test 6: " + err.Error())
		}
	}

	{
		person1ContinentsMap := map[string]float64{}
		person1RegionsMap := map[string]float64{}
		person1SubregionsMap := map[string]float64{
			"Siberian": 100,
		}

		person2ContinentsMap := map[string]float64{}
		person2RegionsMap := map[string]float64{}
		person2SubregionsMap := map[string]float64{
			"Manchurian & Mongolian": 100,
		}

		err := testAncestralSimilarity(person1ContinentsMap, person1RegionsMap, person1SubregionsMap, person2ContinentsMap, person2RegionsMap, person2SubregionsMap, 80)
		if (err != nil){
			t.Fatal("testAncestralSimilarity failed test 7: " + err.Error())
		}
	}

	//TODO: Add more tests.
}



