package createCoupleGeneticAnalysis_test

import "seekia/internal/genetics/createCoupleGeneticAnalysis"

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 TestCreateCoupleGeneticAnalysis_SingleGenomes(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())
	}

	getPersonGenomesList := func()([]prepareRawGenomes.RawGenomeWithMetadata, error){

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

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

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

		personGenomesList := []prepareRawGenomes.RawGenomeWithMetadata{rawGenomeWithMetadata}

		return personGenomesList, nil
	}

	person1GenomesList, err := getPersonGenomesList()
	if (err != nil){
		t.Fatal("getPersonGenomesList failed: " + err.Error())
	}

	person2GenomesList, err := getPersonGenomesList()
	if (err != nil){
		t.Fatal("getPersonGenomesList failed: " + err.Error())
	}

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

	checkIfProcessIsStoppedFunction := func()bool{
		return false
	}

	processCompleted, coupleGeneticAnalysis, err := createCoupleGeneticAnalysis.CreateCoupleGeneticAnalysis(person1GenomesList, person2GenomesList, updateProgressFunction, checkIfProcessIsStoppedFunction)
	if (err != nil){
		t.Fatal("Failed to create couple genetic analysis: " + err.Error())
	}
	if (processCompleted == false){
		t.Fatal("Failed to create couple genetic analysis: Process did not complete.")
	}

	coupleGeneticAnalysisObject, err := readGeneticAnalysis.ReadCoupleGeneticAnalysisString(coupleGeneticAnalysis)
	if (err != nil){
		t.Fatal("Failed to read couple genetic analysis string: " + err.Error())	
	}

	err = readGeneticAnalysis.VerifyCoupleGeneticAnalysis(coupleGeneticAnalysisObject)
	if (err != nil){
		t.Fatal("Failed to read couple genetic analysis: " + err.Error())
	}
}



func TestCreateCoupleGeneticAnalysis_SingleAndMultipleGenomes(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())
	}

	getPersonGenomesList := func(addSecondGenome bool)([]prepareRawGenomes.RawGenomeWithMetadata, error){

		genomeIdentifier1, err := helpers.GetNewRandom16ByteArray()
		if (err != nil) {
			return nil, errors.New("Failed to get random 16 byte array: " + err.Error())
		}

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

		genomeIsValid, rawGenomeWithMetadata1, err := prepareRawGenomes.CreateRawGenomeWithMetadataObject(genomeIdentifier1, fakeRawGenome1)
		if (err != nil){
			return nil, errors.New("CreateRawGenomeWithMetadataObject failed: " + err.Error())
		}
		if (genomeIsValid == false){
			return nil, errors.New("CreateRawGenomeWithMetadataObject failed: Genome is not valid.")
		}

		genomesList := []prepareRawGenomes.RawGenomeWithMetadata{rawGenomeWithMetadata1}

		if (addSecondGenome == true){

			genomeIdentifier2, err := helpers.GetNewRandom16ByteArray()
			if (err != nil) {
				return nil, errors.New("Failed to get random 16 byte array: " + err.Error())
			}

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

			genomeIsValid, rawGenomeWithMetadata2, err := prepareRawGenomes.CreateRawGenomeWithMetadataObject(genomeIdentifier2, fakeRawGenome2)
			if (err != nil){
				return nil, errors.New("CreateRawGenomeWithMetadataObject failed: " + err.Error())
			}
			if (genomeIsValid == false){
				return nil, errors.New("CreateRawGenomeWithMetadataObject failed: Genome is not valid.")
			}

			genomesList = append(genomesList, rawGenomeWithMetadata2)
		}

		return genomesList, nil
	}

	person1GenomesList, err := getPersonGenomesList(false)
	if (err != nil){
		t.Fatal("getPersonGenomesList failed: " + err.Error())
	}

	person2GenomesList, err := getPersonGenomesList(true)
	if (err != nil){
		t.Fatal("getPersonGenomesList failed: " + err.Error())
	}

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

	checkIfProcessIsStoppedFunction := func()bool{
		return false
	}

	processCompleted, coupleGeneticAnalysis, err := createCoupleGeneticAnalysis.CreateCoupleGeneticAnalysis(person1GenomesList, person2GenomesList, updateProgressFunction, checkIfProcessIsStoppedFunction)
	if (err != nil){
		t.Fatal("Failed to create couple genetic analysis: " + err.Error())
	}
	if (processCompleted == false){
		t.Fatal("Failed to create couple genetic analysis: Process did not complete.")
	}

	coupleGeneticAnalysisObject, err := readGeneticAnalysis.ReadCoupleGeneticAnalysisString(coupleGeneticAnalysis)
	if (err != nil){
		t.Fatal("Failed to read couple genetic analysis string: " + err.Error())	
	}

	err = readGeneticAnalysis.VerifyCoupleGeneticAnalysis(coupleGeneticAnalysisObject)
	if (err != nil){
		t.Fatal("Failed to read couple genetic analysis: " + err.Error())
	}
}


func TestCreateCoupleGeneticAnalysis_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())
	}

	getPersonGenomesList := func()([]prepareRawGenomes.RawGenomeWithMetadata, error){

		genomeIdentifier1, err := helpers.GetNewRandom16ByteArray()
		if (err != nil) {
			return nil, errors.New("Failed to get random 16 byte array: " + err.Error())
		}

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

		genomeIsValid, rawGenomeWithMetadata1, err := prepareRawGenomes.CreateRawGenomeWithMetadataObject(genomeIdentifier1, fakeRawGenome1)
		if (err != nil){
			return nil, errors.New("CreateRawGenomeWithMetadataObject failed: " + err.Error())
		}
		if (genomeIsValid == false){
			return nil, errors.New("CreateRawGenomeWithMetadataObject failed: Genome is not valid.")
		}

		genomeIdentifier2, err := helpers.GetNewRandom16ByteArray()
		if (err != nil) {
			return nil, errors.New("Failed to get random 16 byte array: " + err.Error())
		}

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

		genomeIsValid, rawGenomeWithMetadata2, err := prepareRawGenomes.CreateRawGenomeWithMetadataObject(genomeIdentifier2, fakeRawGenome2)
		if (err != nil){
			return nil, errors.New("CreateRawGenomeWithMetadataObject failed: " + err.Error())
		}
		if (genomeIsValid == false){
			return nil, errors.New("CreateRawGenomeWithMetadataObject failed: Genome is not valid.")
		}

		genomesList := []prepareRawGenomes.RawGenomeWithMetadata{rawGenomeWithMetadata1, rawGenomeWithMetadata2}

		return genomesList, nil
	}

	person1GenomesList, err := getPersonGenomesList()
	if (err != nil){
		t.Fatal("getPersonGenomesList failed: " + err.Error())
	}

	person2GenomesList, err := getPersonGenomesList()
	if (err != nil){
		t.Fatal("getPersonGenomesList failed: " + err.Error())
	}

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

	checkIfProcessIsStoppedFunction := func()bool{
		return false
	}

	processCompleted, coupleGeneticAnalysis, err := createCoupleGeneticAnalysis.CreateCoupleGeneticAnalysis(person1GenomesList, person2GenomesList, updateProgressFunction, checkIfProcessIsStoppedFunction)
	if (err != nil){
		t.Fatal("Failed to create couple genetic analysis: " + err.Error())
	}
	if (processCompleted == false){
		t.Fatal("Failed to create couple genetic analysis: Process did not complete.")
	}

	coupleGeneticAnalysisObject, err := readGeneticAnalysis.ReadCoupleGeneticAnalysisString(coupleGeneticAnalysis)
	if (err != nil){
		t.Fatal("Failed to read couple genetic analysis string: " + err.Error())	
	}

	err = readGeneticAnalysis.VerifyCoupleGeneticAnalysis(coupleGeneticAnalysisObject)
	if (err != nil){
		t.Fatal("Failed to read couple genetic analysis: " + err.Error())
	}
}


