package orm

import (
	"testing"
	"time"

	"github.com/jinzhu/gorm"
	"github.com/remogatto/prettytest"
)

type testSuite struct {
	prettytest.Suite
}

func TestRunner(t *testing.T) {
	prettytest.Run(
		t,
		new(testSuite),
	)
}

func (t *testSuite) BeforeAll() {
	var (
		db  *gorm.DB
		err error
	)

	connected := false
	for !connected {
		time.Sleep(10 * time.Second)
		db, err = New("karmen:karmen@/karmen_test?charset=utf8&parseTime=True&loc=Local")
		if err != nil {
			time.Sleep(5 * time.Second)
			continue
		}
		connected = true
	}

	Use(db)
	AutoMigrate()
}

func (t *testSuite) TestDB() {
	t.Not(t.Nil(DB()))
}

func (t *testSuite) TestGetActivityAll() {
	activity, err := GetActivityAll(map[string]string{"id": "1"})
	t.Nil(err)
	if !t.Failed() {
		t.Equal("Amilcare", activity.(*Activity).Teacher.Name)
	}

}

func (t *testSuite) TestGetActivityForUpdate() {
	data, err := GetActivityForUpdate(map[string]string{"id": "1"})
	t.Nil(err)
	if !t.Failed() {
		t.Equal("Amilcare", data.(ActivityForUpdate).Activity.Teacher.Name)
		t.Equal("1 A", data.(ActivityForUpdate).AllClasses[0].Name)
		t.Equal("ITALIANO", data.(ActivityForUpdate).AllSubjects[1].Name)
		t.Equal("Costanza", data.(ActivityForUpdate).AllTeachers[2].Name)
	}

}

func (t *testSuite) TestSaveActivity() {
	activity, err := GetActivity(map[string]string{"id": "1"})
	t.Nil(err)

	t.Equal(uint(1), activity.(*Activity).SubjectID)

	activity.(*Activity).SubjectID = 2
	_, err = SaveActivity(activity)
	t.Nil(err)

	if !t.Failed() {
		activity, _ = GetActivity(map[string]string{"id": "1"})
		t.Equal(uint(2), activity.(*Activity).SubjectID)
	}
}

func (t *testSuite) TestGetTeacher() {
	teacher, err := GetTeacher(map[string]string{"id": "1"})
	t.Nil(err)
	if !t.Failed() {
		t.Equal("Amilcare", teacher.(*Teacher).Name)
		t.Equal("AGOSTINO", teacher.(*Teacher).Surname)
	}

}

func (t *testSuite) TestGetTeacherAll() {
	teacher, err := GetTeacherAll(map[string]string{"id": "1"})
	t.Nil(err)
	if !t.Failed() {
		t.Equal("Amilcare", teacher.(*Teacher).Name)
		t.Equal("AGOSTINO", teacher.(*Teacher).Surname)

		t.Equal("1 A", teacher.(*Teacher).Activities[0].Class.Name)
	}

}

func (t *testSuite) TestGetTeachers() {
	teachers, err := GetTeachers(map[string]string{})
	t.Nil(err)
	t.Equal(9, len(teachers.([]*Teacher)))

	teacher := teachers.([]*Teacher)[0]
	classes, err := teacher.GetClasses()
	t.Nil(err)
	t.Equal(1, len(classes))
	t.Equal(1, len(teacher.Classes))

	class := classes[0]
	t.Equal("1 A", class.Name)
}

func (t *testSuite) TestGetTeachersAll() {
	teachers, err := GetTeachersAll(map[string]string{})
	t.Nil(err)
	t.Equal(9, len(teachers.([]*Teacher)))

	t.Equal("1 A", teachers.([]*Teacher)[0].Classes[0].Name)
	t.Equal("MATEMATICA", teachers.([]*Teacher)[0].Subjects[0].Name)
}

func (t *testSuite) TestGetTeacherActivitiesByClass() {
	teacher, err := GetTeacher(map[string]string{"id": "1"})
	t.Nil(err)
	if !t.Failed() {
		_, err := teacher.(*Teacher).GetActivitiesByClass("1")
		t.Nil(err)
		if !t.Failed() {
			t.True(len(teacher.(*Teacher).Activities) > 0)
		}
	}

}

func (t *testSuite) TestGetClasses() {
	classes, err := GetClasses()
	t.Nil(err)
	t.Equal(1, len(classes))

	class := classes[0]
	teachers, err := class.GetTeachers()
	t.Nil(err)
	t.Equal(9, len(teachers))
	t.Equal(9, len(class.Teachers))

	teacher := teachers[0]
	t.Equal("AGOSTINO", teacher.Surname)

	classes, err = GetClassesAll()
	t.True(len(classes[0].Teachers) > 0)
	if !t.Failed() {
		t.Equal("AGOSTINO", classes[0].Teachers[0].Surname)
	}
}

func (t *testSuite) TestGetClass() {
	class, err := GetClass("1")
	t.Nil(err)
	if !t.Failed() {
		t.Equal("1 A", class.Name)

		// Test teachers

		t.True(len(class.Teachers) > 0)
		t.Equal("AGOSTINO", class.Teachers[0].Surname)
		t.Equal("PETRUZZELLI", class.Teachers[8].Surname)
		t.Equal("LUNGA", class.Coordinator.Surname)
		t.Equal("DONADONI", class.Minuter.Surname)

		// Test activities

		t.True(len(class.Activities) > 0)
		t.Equal("1 A", class.Activities[0].Class.Name)
		t.Equal("AGOSTINO", class.Activities[0].Teacher.Surname)
		t.Equal("MATEMATICA", class.Activities[0].Subject.Name)
		t.Equal(2, class.Activities[0].Hours)
	}

}

func (t *testSuite) TestSaveTeacher() {
	teacher, err := GetTeacher(map[string]string{"id": "1"})
	t.Nil(err)

	teacher.(*Teacher).Name = "Roberto"
	_, err = SaveTeacher(teacher)
	t.Nil(err)

	if !t.Failed() {
		teacher, _ = GetTeacher(map[string]string{"id": "1"})
		t.Equal("Roberto", teacher.(*Teacher).Name)
	}
}

func (t *testSuite) TestCreateDeleteTeacher() {
	teacher := new(Teacher)
	teacher.Name = "Giovanni"
	teacher.Surname = "Giacobbe"

	_, err := CreateTeacher(teacher)
	t.Nil(err)

	if !t.Failed() {
		teacherFromDb, _ := GetTeacher(map[string]string{"id": "10"})
		t.Equal("Giovanni", teacherFromDb.(*Teacher).Name)
		err := DeleteTeacher(teacherFromDb.(*Teacher))
		t.Nil(err)
		teachers, _ := GetTeachers(map[string]string{})
		t.Equal(9, len(teachers.([]*Teacher)))
	}
}
