package services

import (
	"testing"
	"time"

	"github.com/breakpilot/consent-service/internal/models"

	"github.com/google/uuid"
)

// TestGenerateOnboardingToken tests the QR code token generation
func TestGenerateOnboardingToken(t *testing.T) {
	tests := []struct {
		name        string
		studentID   uuid.UUID
		createdBy   uuid.UUID
		role        string
		expectError bool
	}{
		{
			name:        "valid parent token",
			studentID:   uuid.New(),
			createdBy:   uuid.New(),
			role:        "parent",
			expectError: false,
		},
		{
			name:        "valid parent_representative token",
			studentID:   uuid.New(),
			createdBy:   uuid.New(),
			role:        "parent_representative",
			expectError: false,
		},
		{
			name:        "empty student ID",
			studentID:   uuid.Nil,
			createdBy:   uuid.New(),
			role:        "parent",
			expectError: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			token := &models.ParentOnboardingToken{
				StudentID: tt.studentID,
				CreatedBy: tt.createdBy,
				Role:      tt.role,
				ExpiresAt: time.Now().Add(7 * 24 * time.Hour),
			}

			// Validate token fields
			if tt.studentID == uuid.Nil && !tt.expectError {
				t.Errorf("expected error for empty student ID")
			}

			if token.Role != "parent" && token.Role != "parent_representative" {
				if !tt.expectError {
					t.Errorf("invalid role: %s", token.Role)
				}
			}

			// Check expiration is in the future
			if token.ExpiresAt.Before(time.Now()) {
				t.Errorf("token expiration should be in the future")
			}
		})
	}
}

// TestValidateSchoolData tests school data validation
func TestValidateSchoolData(t *testing.T) {
	address1 := "Musterstraße 1, 20095 Hamburg"
	address2 := "Musterstraße 1"
	address3 := "Parkweg 5"

	tests := []struct {
		name        string
		school      models.School
		expectValid bool
	}{
		{
			name: "valid school",
			school: models.School{
				Name:    "Testschule Hamburg",
				Address: &address1,
				Type:    "gymnasium",
			},
			expectValid: true,
		},
		{
			name: "empty name",
			school: models.School{
				Name:    "",
				Address: &address2,
				Type:    "gymnasium",
			},
			expectValid: false,
		},
		{
			name: "valid grundschule",
			school: models.School{
				Name:    "Grundschule Am Park",
				Address: &address3,
				Type:    "grundschule",
			},
			expectValid: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			isValid := validateSchool(tt.school)
			if isValid != tt.expectValid {
				t.Errorf("expected valid=%v, got valid=%v", tt.expectValid, isValid)
			}
		})
	}
}

// validateSchool is a helper function for validation
func validateSchool(school models.School) bool {
	if school.Name == "" {
		return false
	}
	if school.Type == "" {
		return false
	}
	return true
}

// TestValidateClassData tests class data validation
func TestValidateClassData(t *testing.T) {
	tests := []struct {
		name        string
		class       models.Class
		expectValid bool
	}{
		{
			name: "valid class 5a",
			class: models.Class{
				Name:         "5a",
				Grade:        5,
				SchoolID:     uuid.New(),
				SchoolYearID: uuid.New(),
			},
			expectValid: true,
		},
		{
			name: "invalid grade level 0",
			class: models.Class{
				Name:         "0a",
				Grade:        0,
				SchoolID:     uuid.New(),
				SchoolYearID: uuid.New(),
			},
			expectValid: false,
		},
		{
			name: "invalid grade level 14",
			class: models.Class{
				Name:         "14a",
				Grade:        14,
				SchoolID:     uuid.New(),
				SchoolYearID: uuid.New(),
			},
			expectValid: false,
		},
		{
			name: "missing school ID",
			class: models.Class{
				Name:         "5a",
				Grade:        5,
				SchoolID:     uuid.Nil,
				SchoolYearID: uuid.New(),
			},
			expectValid: false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			isValid := validateClass(tt.class)
			if isValid != tt.expectValid {
				t.Errorf("expected valid=%v, got valid=%v", tt.expectValid, isValid)
			}
		})
	}
}

// validateClass is a helper function for class validation
func validateClass(class models.Class) bool {
	if class.Name == "" {
		return false
	}
	if class.Grade < 1 || class.Grade > 13 {
		return false
	}
	if class.SchoolID == uuid.Nil {
		return false
	}
	if class.SchoolYearID == uuid.Nil {
		return false
	}
	return true
}

// TestValidateStudentData tests student data validation
func TestValidateStudentData(t *testing.T) {
	dob := time.Date(2014, 5, 15, 0, 0, 0, 0, time.UTC)
	futureDob := time.Now().AddDate(1, 0, 0)
	studentNum := "2024-001"

	tests := []struct {
		name        string
		student     models.Student
		expectValid bool
	}{
		{
			name: "valid student",
			student: models.Student{
				FirstName:     "Max",
				LastName:      "Mustermann",
				DateOfBirth:   &dob,
				SchoolID:      uuid.New(),
				ClassID:       uuid.New(),
				StudentNumber: &studentNum,
			},
			expectValid: true,
		},
		{
			name: "empty first name",
			student: models.Student{
				FirstName:     "",
				LastName:      "Mustermann",
				DateOfBirth:   &dob,
				SchoolID:      uuid.New(),
				ClassID:       uuid.New(),
				StudentNumber: &studentNum,
			},
			expectValid: false,
		},
		{
			name: "future birth date",
			student: models.Student{
				FirstName:     "Max",
				LastName:      "Mustermann",
				DateOfBirth:   &futureDob,
				SchoolID:      uuid.New(),
				ClassID:       uuid.New(),
				StudentNumber: &studentNum,
			},
			expectValid: false,
		},
		{
			name: "missing class ID",
			student: models.Student{
				FirstName:     "Max",
				LastName:      "Mustermann",
				DateOfBirth:   &dob,
				SchoolID:      uuid.New(),
				ClassID:       uuid.Nil,
				StudentNumber: &studentNum,
			},
			expectValid: false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			isValid := validateStudent(tt.student)
			if isValid != tt.expectValid {
				t.Errorf("expected valid=%v, got valid=%v", tt.expectValid, isValid)
			}
		})
	}
}

// validateStudent is a helper function for student validation
func validateStudent(student models.Student) bool {
	if student.FirstName == "" || student.LastName == "" {
		return false
	}
	if student.DateOfBirth != nil && student.DateOfBirth.After(time.Now()) {
		return false
	}
	if student.ClassID == uuid.Nil {
		return false
	}
	return true
}

// TestValidateTeacherData tests teacher data validation
func TestValidateTeacherData(t *testing.T) {
	code := "SCH"
	codeLong := "SCHMI"

	tests := []struct {
		name        string
		teacher     models.Teacher
		expectValid bool
	}{
		{
			name: "valid teacher",
			teacher: models.Teacher{
				FirstName:   "Anna",
				LastName:    "Schmidt",
				UserID:      uuid.New(),
				TeacherCode: &code,
				SchoolID:    uuid.New(),
			},
			expectValid: true,
		},
		{
			name: "empty first name",
			teacher: models.Teacher{
				FirstName:   "",
				LastName:    "Schmidt",
				UserID:      uuid.New(),
				TeacherCode: &code,
				SchoolID:    uuid.New(),
			},
			expectValid: false,
		},
		{
			name: "teacher code too long",
			teacher: models.Teacher{
				FirstName:   "Anna",
				LastName:    "Schmidt",
				UserID:      uuid.New(),
				TeacherCode: &codeLong,
				SchoolID:    uuid.New(),
			},
			expectValid: false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			isValid := validateTeacher(tt.teacher)
			if isValid != tt.expectValid {
				t.Errorf("expected valid=%v, got valid=%v", tt.expectValid, isValid)
			}
		})
	}
}

// validateTeacher is a helper function for teacher validation
func validateTeacher(teacher models.Teacher) bool {
	if teacher.FirstName == "" || teacher.LastName == "" {
		return false
	}
	if teacher.TeacherCode != nil && len(*teacher.TeacherCode) > 4 {
		return false
	}
	if teacher.SchoolID == uuid.Nil {
		return false
	}
	return true
}

// TestSchoolYearValidation tests school year date validation
func TestSchoolYearValidation(t *testing.T) {
	tests := []struct {
		name        string
		year        models.SchoolYear
		expectValid bool
	}{
		{
			name: "valid school year 2024/2025",
			year: models.SchoolYear{
				Name:      "2024/2025",
				StartDate: time.Date(2024, 8, 1, 0, 0, 0, 0, time.UTC),
				EndDate:   time.Date(2025, 7, 31, 0, 0, 0, 0, time.UTC),
				SchoolID:  uuid.New(),
			},
			expectValid: true,
		},
		{
			name: "end before start",
			year: models.SchoolYear{
				Name:      "2024/2025",
				StartDate: time.Date(2025, 8, 1, 0, 0, 0, 0, time.UTC),
				EndDate:   time.Date(2024, 7, 31, 0, 0, 0, 0, time.UTC),
				SchoolID:  uuid.New(),
			},
			expectValid: false,
		},
		{
			name: "same start and end",
			year: models.SchoolYear{
				Name:      "2024/2025",
				StartDate: time.Date(2024, 8, 1, 0, 0, 0, 0, time.UTC),
				EndDate:   time.Date(2024, 8, 1, 0, 0, 0, 0, time.UTC),
				SchoolID:  uuid.New(),
			},
			expectValid: false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			isValid := validateSchoolYear(tt.year)
			if isValid != tt.expectValid {
				t.Errorf("expected valid=%v, got valid=%v", tt.expectValid, isValid)
			}
		})
	}
}

// validateSchoolYear is a helper function for school year validation
func validateSchoolYear(year models.SchoolYear) bool {
	if year.Name == "" {
		return false
	}
	if year.SchoolID == uuid.Nil {
		return false
	}
	if !year.EndDate.After(year.StartDate) {
		return false
	}
	return true
}
