package orm

import (
	"strconv"
	"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) TestDeleteActivity() {
	var activities []*Activity

	err := DB().Find(&activities).Error
	t.Nil(err)

	numActivities := len(activities)
	activity, err := CreateActivity(
		&Activity{
			SubjectID: 1,
			TeacherID: 1,
			ClassID:   1,
		})
	t.Nil(err)

	err = DB().Find(&activities).Error
	t.Nil(err)

	t.Equal(numActivities+1, len(activities))

	_, err = DeleteActivity(map[string]string{"id": strconv.Itoa(int(activity.ID))}, nil)
	t.Nil(err)

	err = DB().Find(&activities).Error
	t.Nil(err)

	t.Equal(numActivities, len(activities))
}

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)
		t.Equal("1 B", teacher.(*Teacher).Activities[1].Class.Name)

		t.Equal(4, teacher.(*Teacher).ActualHours)
	}

	teacher, err = GetTeacherAll(map[string]string{"id": "3"})
	t.Nil(err)
	if !t.Failed() {
		t.Equal("Costanza", teacher.(*Teacher).Name)
		t.Equal("LUNGA", teacher.(*Teacher).Surname)

		t.Equal(true, teacher.(*Teacher).IsCoordinator)
	}

}

func (t *testSuite) TestGetStudentAll() {
	student, err := GetStudentAll(map[string]string{"id": "1"})
	t.Nil(err)
	if !t.Failed() {
		t.Equal("Mario", student.(*Student).Name)
		t.Equal("ROSSI", student.(*Student).Surname)

		t.Equal("1 A", student.(*Student).Class.Name)
		t.Equal("LUNGA", student.(*Student).Class.Coordinator.Surname)
	}

}

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

	teacher := teachers.([]*Teacher)[0]
	classes, err := teacher.GetClasses()
	t.Nil(err)
	t.Equal(2, len(classes))
	t.Equal(2, 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(11, len(teachers.([]*Teacher)))

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

	t.Equal(1, len(teachers.([]*Teacher)[0].SubjectsByClass[1]))
}

func (t *testSuite) TestGetTeachersFast() {
	teachers, err := GetTeachersFast(map[string]string{})
	t.Nil(err)

	t.Equal(11, len(teachers.([]*Teacher)))
}

func (t *testSuite) TestGetTeacherActByClass() {
	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) TestGetTeacherSubjByClass() {
	teacher, err := GetTeacherAll(map[string]string{"id": "1"})
	t.Nil(err)

	t.Equal(2, len(teacher.(*Teacher).Subjects))

	if !t.Failed() {
		subjects, err := teacher.(*Teacher).GetSubjectsByClassID("1")
		t.Nil(err)
		if !t.Failed() {
			t.Equal(1, len(subjects))
		}
	}

}

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, err := CreateTeacher(&Teacher{Credential: Credential{Name: "Giovanni", Surname: "GIACOBBE"}})
	t.Nil(err)

	if !t.Failed() {
		_, err = DeleteTeacher(map[string]string{"id": strconv.Itoa(int(teacher.ID))}, nil)
		t.Nil(err)
		teachers, _ := GetTeachers(map[string]string{})
		t.Equal(11, len(teachers.([]*Teacher)))
	}

	teacher, err = CreateTeacher(&Teacher{Credential: Credential{Name: "Amilcare", Surname: "AGOSTINO"}})
	t.Not(t.Nil(err))
}

func (t *testSuite) TestGetDepartments() {
	departments, err := GetDepartments(map[string]string{})
	t.Nil(err)
	t.Equal(2, len(departments.([]*Department)))

	if !t.Failed() {
		department := departments.([]*Department)[0]
		subjects, err := department.GetSubjects()
		t.Nil(err)
		t.Equal(1, len(subjects))
		t.Equal(1, len(department.Subjects))

		subject := subjects[0]
		t.Equal("FRANCESE", subject.Name)
	}
}

func (t *testSuite) TestGetDepartment() {
	department, err := GetDepartment(map[string]string{"id": "1"})
	t.Nil(err)
	if !t.Failed() {
		t.Equal("LINGUE STRANIERE", department.(*Department).Name)
	}

}

func (t *testSuite) TestGetDepartmentAll() {
	department, err := GetDepartmentAll(map[string]string{"id": "1"})
	t.Nil(err)
	if !t.Failed() {
		t.Equal("FRANCESE", department.(*Department).Subjects[0].Name)
		t.Equal("DELLE ROSE", department.(*Department).Teachers[0].Surname)
	}

}

func (t *testSuite) TestGetSubjectForAdd() {
	data, err := GetSubjectForAdd(nil)
	t.Nil(err)
	if !t.Failed() {
		t.Equal("LINGUE STRANIERE", data.(SubjectForAdd).AllDepartments[0].Name)
	}

}

func (t *testSuite) TestSaveStudent() {
	student, err := GetStudentAll(map[string]string{"id": "1"})
	t.Nil(err)

	t.Equal(uint(1), student.(*Student).ClassID)

	student.(*Student).ClassID = 2
	student.(*Student).Handicap = true
	_, err = SaveStudent(student)
	t.Nil(err)

	if !t.Failed() {
		student, _ = GetStudent(map[string]string{"id": "1"})
		t.Equal(uint(2), student.(*Student).ClassID)
		t.Equal(true, student.(*Student).Handicap)
	}
}
