package createPersonGeneticAnalysis_test

import "seekia/internal/genetics/createPersonGeneticAnalysis"

import "seekia/internal/genetics/readGeneticAnalysis"
import "seekia/internal/genetics/geneticReferences/locusMetadata"
import "seekia/internal/genetics/geneticReferences/monogenicDiseases"
import "seekia/internal/genetics/geneticReferences/polygenicDiseases"
import "seekia/internal/genetics/geneticReferences/traits"
import "seekia/internal/genetics/trainedPredictionModels"
import "seekia/internal/genetics/createRawGenomes"
import "seekia/internal/genetics/prepareRawGenomes"
import "seekia/internal/helpers"

import "testing"
import "errors"


func TestCreatePersonGeneticAnalysis_SingleGenome(t *testing.T){

	err := locusMetadata.InitializeLocusMetadataVariables()
	if (err != nil) {
		t.Fatal("InitializeLocusMetadataVariables failed: " + err.Error())
	}

	monogenicDiseases.InitializeMonogenicDiseaseVariables()

	err = polygenicDiseases.InitializePolygenicDiseaseVariables()	
	if (err != nil) {
		t.Fatal("InitializePolygenicDiseaseVariables failed: " + err.Error())
	}

	err = traits.InitializeTraitVariables()
	if (err != nil) {
		t.Fatal("InitializeTraitVariables failed: " + err.Error())
	}

	err = trainedPredictionModels.InitializeTrainedPredictionModels()
	if (err != nil) {
		t.Fatal("InitializeTrainedPredictionModels failed: " + err.Error())
	}

	genomeIdentifier, err := helpers.GetNewRandom16ByteArray()
	if (err != nil) {
		t.Fatal("Failed to get random 16 byte array: " + err.Error())
	}

	fakeRawGenome, _, _, _, err := createRawGenomes.CreateFakeRawGenome_AncestryDNA()
	if (err != nil) {
		t.Fatal("Failed to create fake raw AncestryDNA genome: " + err.Error())
	}

	genomeIsValid, rawGenomeWithMetadata, err := prepareRawGenomes.CreateRawGenomeWithMetadataObject(genomeIdentifier, fakeRawGenome)
	if (err != nil){
		t.Fatal("CreateRawGenomeWithMetadataObject failed: " + err.Error())
	}
	if (genomeIsValid == false){
		t.Fatal("CreateRawGenomeWithMetadataObject failed: Genome is not valid.")
	}

	genomesList := []prepareRawGenomes.RawGenomeWithMetadata{rawGenomeWithMetadata}

	updateProgressFunction := func(_ int)error{
		return nil
	}

	checkIfProcessIsStoppedFunction := func()bool{
		return false
	}

	processCompleted, personGeneticAnalysis, err := createPersonGeneticAnalysis.CreatePersonGeneticAnalysis(genomesList, updateProgressFunction, checkIfProcessIsStoppedFunction)
	if (err != nil){
		t.Fatal("Failed to create person genetic analysis: " + err.Error())
	}
	if (processCompleted == false){
		t.Fatal("Failed to create person genetic analysis: Process did not complete.")
	}

	personGeneticAnalysisObject, err := readGeneticAnalysis.ReadPersonGeneticAnalysisString(personGeneticAnalysis)
	if (err != nil){
		t.Fatal("Failed to read person genetic analysis string: " + err.Error())	
	}

	err = readGeneticAnalysis.VerifyPersonGeneticAnalysis(personGeneticAnalysisObject)
	if (err != nil){
		t.Fatal("Failed to read person genetic analysis: " + err.Error())
	}
}


func TestCreatePersonGeneticAnalysis_MultipleGenomes(t *testing.T){

	err := locusMetadata.InitializeLocusMetadataVariables()
	if (err != nil) {
		t.Fatal("InitializeLocusMetadataVariables failed: " + err.Error())
	}

	monogenicDiseases.InitializeMonogenicDiseaseVariables()

	err = polygenicDiseases.InitializePolygenicDiseaseVariables()	
	if (err != nil) {
		t.Fatal("InitializePolygenicDiseaseVariables failed: " + err.Error())
	}

	err = traits.InitializeTraitVariables()
	if (err != nil) {
		t.Fatal("InitializeTraitVariables failed: " + err.Error())
	}

	err = trainedPredictionModels.InitializeTrainedPredictionModels()
	if (err != nil) {
		t.Fatal("InitializeTrainedPredictionModels failed: " + err.Error())
	}

	numberOfGenomesToAdd := helpers.GetRandomIntWithinRange(2, 5)

	genomesList := make([]prepareRawGenomes.RawGenomeWithMetadata, 0, numberOfGenomesToAdd)

	for i:=0; i < numberOfGenomesToAdd; i++{

		genomeIdentifier, err := helpers.GetNewRandom16ByteArray()
		if (err != nil) {
			t.Fatal("Failed to get random 16 byte array: " + err.Error())
		}

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

			is23andMe := helpers.GetRandomBool()
			if (is23andMe == true){
				fakeRawGenome, _, _, _, err := createRawGenomes.CreateFakeRawGenome_23andMe()
				if (err != nil) {
					return "", errors.New("Failed to create fake raw 23andMe genome: " + err.Error())
				}

				return fakeRawGenome, nil
			}

			fakeRawGenome, _, _, _, err := createRawGenomes.CreateFakeRawGenome_AncestryDNA()
			if (err != nil) {
				return "", errors.New("Failed to create fake raw AncestryDNA genome: " + err.Error())
			}

			return fakeRawGenome, nil
		}

		fakeRawGenome, err := getFakeRawGenome()
		if (err != nil){
			t.Fatal("Failed to get fake raw genome: " + err.Error())
		}

		genomeIsValid, rawGenomeWithMetadata, err := prepareRawGenomes.CreateRawGenomeWithMetadataObject(genomeIdentifier, fakeRawGenome)
		if (err != nil){
			t.Fatal("CreateRawGenomeWithMetadataObject failed: " + err.Error())
		}
		if (genomeIsValid == false){
			t.Fatal("CreateRawGenomeWithMetadataObject failed: Genome is not valid.")
		}

		genomesList = append(genomesList, rawGenomeWithMetadata)
	}

	updateProgressFunction := func(_ int)error{
		return nil
	}

	checkIfProcessIsStoppedFunction := func()bool{
		return false
	}

	processCompleted, personGeneticAnalysis, err := createPersonGeneticAnalysis.CreatePersonGeneticAnalysis(genomesList, updateProgressFunction, checkIfProcessIsStoppedFunction)
	if (err != nil){
		t.Fatal("Failed to create person genetic analysis: " + err.Error())
	}
	if (processCompleted == false){
		t.Fatal("Failed to create person genetic analysis: Process did not complete.")
	}

	personGeneticAnalysisObject, err := readGeneticAnalysis.ReadPersonGeneticAnalysisString(personGeneticAnalysis)
	if (err != nil){
		t.Fatal("Failed to read person genetic analysis string: " + err.Error())	
	}

	err = readGeneticAnalysis.VerifyPersonGeneticAnalysis(personGeneticAnalysisObject)
	if (err != nil){
		t.Fatal("Failed to read person genetic analysis: " + err.Error())
	}
}


