package nucleus

import (
	"context"
	"testing"

	"code.fbi.h-da.de/danet/gosdn/controller/interfaces/plugin"
	"code.fbi.h-da.de/danet/gosdn/controller/mocks"
	"code.fbi.h-da.de/danet/gosdn/controller/store"
	"github.com/google/uuid"
	"go.mongodb.org/mongo-driver/mongo"
)

func ensureStoreFilesForTestsAreRemoved() {
	ensureStoreFileForTestsIsRemoved(store.PluginFilenameSuffix)
	ensureStoreFileForTestsIsRemoved(store.NetworkElementFilenameSuffix)
}

func TestAddPlugin(t *testing.T) {
	defer ensureStoreFilesForTestsAreRemoved()

	pluginStore := NewPluginStore(&mongo.Database{})
	mockPlugin := mockPlugin(t)

	err := pluginStore.Add(context.TODO(), mockPlugin)
	if err != nil {
		t.Error(err)
	}
}

func TestGetAllPlugins(t *testing.T) {
	defer ensureStoreFilesForTestsAreRemoved()

	pluginStore := NewPluginStore(&mongo.Database{})

	mockPlugin1ID, err := uuid.Parse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa")
	if err != nil {
		t.Error(err)
	}
	mockPlugin2ID, err := uuid.Parse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaab")
	if err != nil {
		t.Error(err)
	}

	mockPlugin1 := new(mocks.Plugin)
	mockPlugin2 := new(mocks.Plugin)
	mockPlugin1.On("ID").Return(mockPlugin1ID)
	mockPlugin2.On("ID").Return(mockPlugin2ID)

	inputPlugins := [2]plugin.Plugin{mockPlugin1, mockPlugin2}

	for _, plugin := range inputPlugins {
		err := pluginStore.Add(context.TODO(), plugin)
		if err != nil {
			t.Error(err)
		}
	}

	returnPlugins, err := pluginStore.GetAll(context.TODO())
	if err != nil {
		t.Error(err)
	}

	length := len(returnPlugins)
	if length != 2 {
		t.Errorf("GetAll() length of array = %v, want %v", length, 2)
	}

	for i, sbi := range returnPlugins {
		if sbi.ID != inputPlugins[i].ID().String() {
			t.Errorf("GetAll() = %v, want %v", sbi.ID, inputPlugins[i].ID().String())
		}
	}
}

func TestGetPlugin(t *testing.T) {
	defer ensureStoreFilesForTestsAreRemoved()

	pluginStore := NewPluginStore(&mongo.Database{})

	mockPlugin1ID, err := uuid.Parse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa")
	if err != nil {
		t.Error(err)
	}
	mockPlugin2ID, err := uuid.Parse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaab")
	if err != nil {
		t.Error(err)
	}
	mockPlugin1 := &mocks.Plugin{}
	mockPlugin1.On("ID").Return(mockPlugin1ID)
	mockPlugin2 := &mocks.Plugin{}
	mockPlugin2.On("ID").Return(mockPlugin2ID)

	inputPlugins := [2]plugin.Plugin{mockPlugin1, mockPlugin2}

	for _, plugins := range inputPlugins {
		err := pluginStore.Add(context.TODO(), plugins)
		if err != nil {
			t.Error(err)
		}
	}

	returnPlugin, err := pluginStore.Get(context.TODO(), store.Query{ID: mockPlugin2ID, Name: ""})
	if err != nil {
		t.Error(err)
	}

	if returnPlugin.ID != mockPlugin2.ID().String() {
		t.Errorf("Get() = %v, want %v", returnPlugin.ID, mockPlugin2.ID().String())
	}
}

func TestDeleteAllPlugins(t *testing.T) {
	defer ensureStoreFilesForTestsAreRemoved()

	pluginStore := NewPluginStore(&mongo.Database{})

	mockPlugin1ID, err := uuid.Parse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa")
	if err != nil {
		t.Error(err)
	}
	mockPlugin2ID, err := uuid.Parse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaab")
	if err != nil {
		t.Error(err)
	}
	mockPlugin1 := mockPlugin(t)
	mockPlugin1.(*mocks.Plugin).On("ID").Return(mockPlugin1ID)
	mockPlugin2 := mockPlugin(t)
	mockPlugin2.(*mocks.Plugin).On("ID").Return(mockPlugin2ID)

	inputPlugins := [2]plugin.Plugin{mockPlugin1, mockPlugin2}

	for _, plugins := range inputPlugins {
		err := pluginStore.Add(context.TODO(), plugins)
		if err != nil {
			t.Error(err)
		}
	}

	err = pluginStore.Delete(context.TODO(), mockPlugin1)
	if err != nil {
		t.Error(err)
	}

	returnPlugins, err := pluginStore.GetAll(context.TODO())
	if err != nil {
		t.Error(err)
	}

	length := len(returnPlugins)
	if length != 1 {
		t.Errorf("GetAll() length of array = %v, want %v", length, 2)
	}

	if returnPlugins[0].ID != inputPlugins[1].ID().String() {
		t.Errorf("GetAll() = %v, want %v", returnPlugins[0].ID, inputPlugins[1].ID().String())
	}
}