package myMap_test

import "seekia/internal/myDatastores/myMap"

import "seekia/internal/appUsers"
import "seekia/internal/localFilesystem"
import "seekia/internal/helpers"

import "testing"
import "sync"

func TestMyMap(t *testing.T) {
	
	err := localFilesystem.InitializeAppDatastores()
	if (err != nil){
		t.Fatal("Failed to initialize app datastores: " + err.Error())
	}
	err = appUsers.InitializeAppUserForTests(false, false)
	if (err != nil){
		t.Fatal("Failed to initalize app user for tests: " + err.Error())
	}

	newMapObject, err := myMap.CreateNewMap("TestMap")
	if (err != nil) {
		t.Fatal("Failed to create new map: " + err.Error())
	}

	err = newMapObject.DeleteMap()
	if (err != nil) {
		t.Fatal("Failed to delete map: " + err.Error())
	}

	_, err = newMapObject.GetMap()
	if (err != nil) {
		t.Fatal("Failed to get new map: " + err.Error())
	}

	err = newMapObject.SetMapEntry("TestKeyA", "TestValueA")
	if (err != nil) {
		t.Fatal("Failed to add map entry: " + err.Error())
	}

	err = newMapObject.SetMapEntry("TestKeyB", "TestValueB")
	if (err != nil) {
		t.Fatal("Failed to add map entry: " + err.Error())
	}

	exists, entryValue, err := newMapObject.GetMapEntry("TestKeyA")
	if (err != nil) {
		t.Fatal("Failed to get map value: " + err.Error())
	}
	if (exists == false) {
		t.Fatal("Failed to get map value.")
	}

	if (entryValue != "TestValueA"){ 
		 t.Fatal("Map value does not match.")
	}

	err = newMapObject.DeleteMapEntry("TestKeyA")
	if (err != nil){
		t.Fatal("Failed to delete map entry: " + err.Error())
	}

	exists, _, err = newMapObject.GetMapEntry("TestKeyA")
	if (err != nil) {
		t.Fatal("Failed to get map value: " + err.Error())
	}
	if (exists == true) {
		t.Fatal("Failed to delete map value.")
	}

	err = newMapObject.DeleteMap()
	if (err != nil) {
		t.Fatal("Failed to delete map: " + err.Error())
	}	
	
	exists, _, err = newMapObject.GetMapEntry("TestKeyB")
	if (err != nil) {
		t.Fatal("Failed to get map entry: " + err.Error())
	}
	if (exists == true) {
		t.Fatal("Failed to delete map.")
	}

	// Now we test concurrency

	err = newMapObject.SetMapEntry("TestA", "TestB")
	if (err != nil) {
		t.Fatal("Failed to add map entry: " + err.Error())
	}

	currentMap, err := newMapObject.GetMap()
	if (err != nil) {
		t.Fatal("Failed to get map: " + err.Error())
	}

	var mapWaitgroup sync.WaitGroup

	var errorMutex sync.Mutex
	var errorEncountered error

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

		mapWaitgroup.Add(1)

		indexString := helpers.ConvertIntToString(i)

		addFunction := func(){

			err := newMapObject.SetMapEntry("TestKey" + indexString, "TestValue" + indexString)
			if (err != nil) {
				errorMutex.Lock()
				errorEncountered = err
				errorMutex.Unlock()
			}

			mapWaitgroup.Done()
		}

		go addFunction()
	}

	mapWaitgroup.Wait()

	if (errorEncountered != nil){
		t.Fatal(errorEncountered.Error())
	}

	if (len(currentMap) != 1){
		t.Fatal("Map not copied.")
	}

	err = newMapObject.DeleteMap()
	if (err != nil) {
		t.Fatal("Failed to delete map: " + err.Error())
	}
}



