package handlers

import (
	"net/http"
	"time"

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

	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
)

// SchoolHandlers contains all school-related HTTP handlers
type SchoolHandlers struct {
	schoolService     *services.SchoolService
	attendanceService *services.AttendanceService
	gradeService      *services.GradeService
}

// NewSchoolHandlers creates new school handlers
func NewSchoolHandlers(schoolService *services.SchoolService, attendanceService *services.AttendanceService, gradeService *services.GradeService) *SchoolHandlers {
	return &SchoolHandlers{
		schoolService:     schoolService,
		attendanceService: attendanceService,
		gradeService:      gradeService,
	}
}

// ========================================
// School Handlers
// ========================================

// CreateSchool creates a new school
// POST /api/v1/schools
func (h *SchoolHandlers) CreateSchool(c *gin.Context) {
	var req models.CreateSchoolRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	school, err := h.schoolService.CreateSchool(c.Request.Context(), req)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusCreated, school)
}

// GetSchool retrieves a school by ID
// GET /api/v1/schools/:id
func (h *SchoolHandlers) GetSchool(c *gin.Context) {
	idStr := c.Param("id")
	id, err := uuid.Parse(idStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid school ID"})
		return
	}

	school, err := h.schoolService.GetSchool(c.Request.Context(), id)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, school)
}

// ListSchools lists all schools
// GET /api/v1/schools
func (h *SchoolHandlers) ListSchools(c *gin.Context) {
	schools, err := h.schoolService.ListSchools(c.Request.Context())
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, schools)
}

// ========================================
// School Year Handlers
// ========================================

// CreateSchoolYear creates a new school year
// POST /api/v1/schools/:id/years
func (h *SchoolHandlers) CreateSchoolYear(c *gin.Context) {
	schoolIDStr := c.Param("id")
	schoolID, err := uuid.Parse(schoolIDStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid school ID"})
		return
	}

	var req struct {
		Name      string `json:"name" binding:"required"`
		StartDate string `json:"start_date" binding:"required"`
		EndDate   string `json:"end_date" binding:"required"`
	}

	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	startDate, err := time.Parse("2006-01-02", req.StartDate)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid start date format"})
		return
	}

	endDate, err := time.Parse("2006-01-02", req.EndDate)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid end date format"})
		return
	}

	schoolYear, err := h.schoolService.CreateSchoolYear(c.Request.Context(), schoolID, req.Name, startDate, endDate)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusCreated, schoolYear)
}

// SetCurrentSchoolYear sets a school year as current
// PUT /api/v1/schools/:id/years/:yearId/current
func (h *SchoolHandlers) SetCurrentSchoolYear(c *gin.Context) {
	schoolIDStr := c.Param("id")
	schoolID, err := uuid.Parse(schoolIDStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid school ID"})
		return
	}

	yearIDStr := c.Param("yearId")
	yearID, err := uuid.Parse(yearIDStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid school year ID"})
		return
	}

	if err := h.schoolService.SetCurrentSchoolYear(c.Request.Context(), schoolID, yearID); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "school year set as current"})
}

// ========================================
// Class Handlers
// ========================================

// CreateClass creates a new class
// POST /api/v1/schools/:id/classes
func (h *SchoolHandlers) CreateClass(c *gin.Context) {
	schoolIDStr := c.Param("id")
	schoolID, err := uuid.Parse(schoolIDStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid school ID"})
		return
	}

	var req models.CreateClassRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	class, err := h.schoolService.CreateClass(c.Request.Context(), schoolID, req)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusCreated, class)
}

// GetClass retrieves a class by ID
// GET /api/v1/classes/:id
func (h *SchoolHandlers) GetClass(c *gin.Context) {
	idStr := c.Param("id")
	id, err := uuid.Parse(idStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid class ID"})
		return
	}

	class, err := h.schoolService.GetClass(c.Request.Context(), id)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, class)
}

// ListClasses lists all classes for a school in a school year
// GET /api/v1/schools/:id/classes?school_year_id=...
func (h *SchoolHandlers) ListClasses(c *gin.Context) {
	schoolIDStr := c.Param("id")
	schoolID, err := uuid.Parse(schoolIDStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid school ID"})
		return
	}

	schoolYearIDStr := c.Query("school_year_id")
	if schoolYearIDStr == "" {
		// Get current school year
		schoolYear, err := h.schoolService.GetCurrentSchoolYear(c.Request.Context(), schoolID)
		if err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "no current school year set"})
			return
		}
		schoolYearIDStr = schoolYear.ID.String()
	}

	schoolYearID, err := uuid.Parse(schoolYearIDStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid school year ID"})
		return
	}

	classes, err := h.schoolService.ListClasses(c.Request.Context(), schoolID, schoolYearID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, classes)
}

// ========================================
// Student Handlers
// ========================================

// CreateStudent creates a new student
// POST /api/v1/schools/:id/students
func (h *SchoolHandlers) CreateStudent(c *gin.Context) {
	schoolIDStr := c.Param("id")
	schoolID, err := uuid.Parse(schoolIDStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid school ID"})
		return
	}

	var req models.CreateStudentRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	student, err := h.schoolService.CreateStudent(c.Request.Context(), schoolID, req)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusCreated, student)
}

// GetStudent retrieves a student by ID
// GET /api/v1/students/:id
func (h *SchoolHandlers) GetStudent(c *gin.Context) {
	idStr := c.Param("id")
	id, err := uuid.Parse(idStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid student ID"})
		return
	}

	student, err := h.schoolService.GetStudent(c.Request.Context(), id)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, student)
}

// ListStudentsByClass lists all students in a class
// GET /api/v1/classes/:id/students
func (h *SchoolHandlers) ListStudentsByClass(c *gin.Context) {
	classIDStr := c.Param("id")
	classID, err := uuid.Parse(classIDStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid class ID"})
		return
	}

	students, err := h.schoolService.ListStudentsByClass(c.Request.Context(), classID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, students)
}

// ========================================
// Subject Handlers
// ========================================

// CreateSubject creates a new subject
// POST /api/v1/schools/:id/subjects
func (h *SchoolHandlers) CreateSubject(c *gin.Context) {
	schoolIDStr := c.Param("id")
	schoolID, err := uuid.Parse(schoolIDStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid school ID"})
		return
	}

	var req struct {
		Name      string  `json:"name" binding:"required"`
		ShortName string  `json:"short_name" binding:"required"`
		Color     *string `json:"color"`
	}

	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	subject, err := h.schoolService.CreateSubject(c.Request.Context(), schoolID, req.Name, req.ShortName, req.Color)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusCreated, subject)
}

// ListSubjects lists all subjects for a school
// GET /api/v1/schools/:id/subjects
func (h *SchoolHandlers) ListSubjects(c *gin.Context) {
	schoolIDStr := c.Param("id")
	schoolID, err := uuid.Parse(schoolIDStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid school ID"})
		return
	}

	subjects, err := h.schoolService.ListSubjects(c.Request.Context(), schoolID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, subjects)
}

// ========================================
// Attendance Handlers
// ========================================

// RecordAttendance records attendance for a student
// POST /api/v1/attendance
func (h *SchoolHandlers) RecordAttendance(c *gin.Context) {
	userID, exists := c.Get("user_id")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "user not authenticated"})
		return
	}

	var req models.RecordAttendanceRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	record, err := h.attendanceService.RecordAttendance(c.Request.Context(), req, userID.(uuid.UUID))
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusCreated, record)
}

// RecordBulkAttendance records attendance for multiple students
// POST /api/v1/classes/:id/attendance
func (h *SchoolHandlers) RecordBulkAttendance(c *gin.Context) {
	userID, exists := c.Get("user_id")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "user not authenticated"})
		return
	}

	classIDStr := c.Param("id")
	classID, err := uuid.Parse(classIDStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid class ID"})
		return
	}

	var req struct {
		Date    string `json:"date" binding:"required"`
		SlotID  string `json:"slot_id" binding:"required"`
		Records []struct {
			StudentID string  `json:"student_id"`
			Status    string  `json:"status"`
			Note      *string `json:"note"`
		} `json:"records" binding:"required"`
	}

	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	slotID, err := uuid.Parse(req.SlotID)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid slot ID"})
		return
	}

	// Convert to the expected type (without JSON tags)
	records := make([]struct {
		StudentID string
		Status    string
		Note      *string
	}, len(req.Records))
	for i, r := range req.Records {
		records[i] = struct {
			StudentID string
			Status    string
			Note      *string
		}{
			StudentID: r.StudentID,
			Status:    r.Status,
			Note:      r.Note,
		}
	}

	err = h.attendanceService.RecordBulkAttendance(c.Request.Context(), classID, req.Date, slotID, records, userID.(uuid.UUID))
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "attendance recorded"})
}

// GetClassAttendance gets attendance for a class on a specific date
// GET /api/v1/classes/:id/attendance?date=...
func (h *SchoolHandlers) GetClassAttendance(c *gin.Context) {
	classIDStr := c.Param("id")
	classID, err := uuid.Parse(classIDStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid class ID"})
		return
	}

	date := c.Query("date")
	if date == "" {
		date = time.Now().Format("2006-01-02")
	}

	overview, err := h.attendanceService.GetAttendanceByClass(c.Request.Context(), classID, date)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, overview)
}

// GetStudentAttendance gets attendance history for a student
// GET /api/v1/students/:id/attendance?start_date=...&end_date=...
func (h *SchoolHandlers) GetStudentAttendance(c *gin.Context) {
	studentIDStr := c.Param("id")
	studentID, err := uuid.Parse(studentIDStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid student ID"})
		return
	}

	startDateStr := c.Query("start_date")
	endDateStr := c.Query("end_date")

	var startDate, endDate time.Time
	if startDateStr == "" {
		startDate = time.Now().AddDate(0, -1, 0) // Last month
	} else {
		startDate, _ = time.Parse("2006-01-02", startDateStr)
	}

	if endDateStr == "" {
		endDate = time.Now()
	} else {
		endDate, _ = time.Parse("2006-01-02", endDateStr)
	}

	records, err := h.attendanceService.GetStudentAttendance(c.Request.Context(), studentID, startDate, endDate)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, records)
}

// ========================================
// Absence Report Handlers
// ========================================

// ReportAbsence allows parents to report absence
// POST /api/v1/absence/report
func (h *SchoolHandlers) ReportAbsence(c *gin.Context) {
	userID, exists := c.Get("user_id")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "user not authenticated"})
		return
	}

	var req models.ReportAbsenceRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	report, err := h.attendanceService.ReportAbsence(c.Request.Context(), req, userID.(uuid.UUID))
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusCreated, report)
}

// ConfirmAbsence allows teachers to confirm absence
// PUT /api/v1/absence/:id/confirm
func (h *SchoolHandlers) ConfirmAbsence(c *gin.Context) {
	userID, exists := c.Get("user_id")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "user not authenticated"})
		return
	}

	reportIDStr := c.Param("id")
	reportID, err := uuid.Parse(reportIDStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid report ID"})
		return
	}

	var req struct {
		Status string `json:"status" binding:"required"` // "excused" or "unexcused"
	}

	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	err = h.attendanceService.ConfirmAbsence(c.Request.Context(), reportID, userID.(uuid.UUID), req.Status)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "absence confirmed"})
}

// GetPendingAbsenceReports gets pending absence reports for a class
// GET /api/v1/classes/:id/absence/pending
func (h *SchoolHandlers) GetPendingAbsenceReports(c *gin.Context) {
	classIDStr := c.Param("id")
	classID, err := uuid.Parse(classIDStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid class ID"})
		return
	}

	reports, err := h.attendanceService.GetPendingAbsenceReports(c.Request.Context(), classID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, reports)
}

// ========================================
// Grade Handlers
// ========================================

// CreateGrade creates a new grade
// POST /api/v1/grades
func (h *SchoolHandlers) CreateGrade(c *gin.Context) {
	userID, exists := c.Get("user_id")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "user not authenticated"})
		return
	}

	var req models.CreateGradeRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	// Get teacher ID from user ID
	teacher, err := h.schoolService.GetTeacherByUserID(c.Request.Context(), userID.(uuid.UUID))
	if err != nil {
		c.JSON(http.StatusForbidden, gin.H{"error": "user is not a teacher"})
		return
	}

	grade, err := h.gradeService.CreateGrade(c.Request.Context(), req, teacher.ID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusCreated, grade)
}

// GetStudentGrades gets all grades for a student
// GET /api/v1/students/:id/grades?school_year_id=...
func (h *SchoolHandlers) GetStudentGrades(c *gin.Context) {
	studentIDStr := c.Param("id")
	studentID, err := uuid.Parse(studentIDStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid student ID"})
		return
	}

	schoolYearIDStr := c.Query("school_year_id")
	if schoolYearIDStr == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "school_year_id is required"})
		return
	}

	schoolYearID, err := uuid.Parse(schoolYearIDStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid school year ID"})
		return
	}

	grades, err := h.gradeService.GetStudentGrades(c.Request.Context(), studentID, schoolYearID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, grades)
}

// GetClassGrades gets grades for all students in a class for a subject (Notenspiegel)
// GET /api/v1/classes/:id/grades/:subjectId?school_year_id=...&semester=...
func (h *SchoolHandlers) GetClassGrades(c *gin.Context) {
	classIDStr := c.Param("id")
	classID, err := uuid.Parse(classIDStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid class ID"})
		return
	}

	subjectIDStr := c.Param("subjectId")
	subjectID, err := uuid.Parse(subjectIDStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid subject ID"})
		return
	}

	schoolYearIDStr := c.Query("school_year_id")
	if schoolYearIDStr == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "school_year_id is required"})
		return
	}

	schoolYearID, err := uuid.Parse(schoolYearIDStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid school year ID"})
		return
	}

	semesterStr := c.DefaultQuery("semester", "1")
	var semester int
	if semesterStr == "1" {
		semester = 1
	} else {
		semester = 2
	}

	overviews, err := h.gradeService.GetClassGradesBySubject(c.Request.Context(), classID, subjectID, schoolYearID, semester)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, overviews)
}

// GetGradeStatistics gets grade statistics for a class/subject
// GET /api/v1/classes/:id/grades/:subjectId/stats?school_year_id=...&semester=...
func (h *SchoolHandlers) GetGradeStatistics(c *gin.Context) {
	classIDStr := c.Param("id")
	classID, err := uuid.Parse(classIDStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid class ID"})
		return
	}

	subjectIDStr := c.Param("subjectId")
	subjectID, err := uuid.Parse(subjectIDStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid subject ID"})
		return
	}

	schoolYearIDStr := c.Query("school_year_id")
	if schoolYearIDStr == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "school_year_id is required"})
		return
	}

	schoolYearID, err := uuid.Parse(schoolYearIDStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid school year ID"})
		return
	}

	semesterStr := c.DefaultQuery("semester", "1")
	var semester int
	if semesterStr == "1" {
		semester = 1
	} else {
		semester = 2
	}

	stats, err := h.gradeService.GetSubjectGradeStatistics(c.Request.Context(), classID, subjectID, schoolYearID, semester)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, stats)
}

// ========================================
// Parent Onboarding Handlers
// ========================================

// GenerateOnboardingToken generates a QR code token for parent onboarding
// POST /api/v1/onboarding/tokens
func (h *SchoolHandlers) GenerateOnboardingToken(c *gin.Context) {
	userID, exists := c.Get("user_id")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "user not authenticated"})
		return
	}

	var req struct {
		SchoolID  string `json:"school_id" binding:"required"`
		ClassID   string `json:"class_id" binding:"required"`
		StudentID string `json:"student_id" binding:"required"`
		Role      string `json:"role"` // "parent" or "parent_representative"
	}

	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	schoolID, err := uuid.Parse(req.SchoolID)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid school ID"})
		return
	}

	classID, err := uuid.Parse(req.ClassID)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid class ID"})
		return
	}

	studentID, err := uuid.Parse(req.StudentID)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid student ID"})
		return
	}

	role := req.Role
	if role == "" {
		role = "parent"
	}

	token, err := h.schoolService.GenerateParentOnboardingToken(c.Request.Context(), schoolID, classID, studentID, userID.(uuid.UUID), role)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	// Generate QR code URL
	qrURL := "/onboard-parent?token=" + token.Token

	c.JSON(http.StatusCreated, gin.H{
		"token":      token.Token,
		"qr_url":     qrURL,
		"expires_at": token.ExpiresAt,
	})
}

// ValidateOnboardingToken validates an onboarding token
// GET /api/v1/onboarding/validate?token=...
func (h *SchoolHandlers) ValidateOnboardingToken(c *gin.Context) {
	token := c.Query("token")
	if token == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "token is required"})
		return
	}

	onboardingToken, err := h.schoolService.ValidateOnboardingToken(c.Request.Context(), token)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "invalid or expired token"})
		return
	}

	// Get student and school info
	student, err := h.schoolService.GetStudent(c.Request.Context(), onboardingToken.StudentID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	class, err := h.schoolService.GetClass(c.Request.Context(), onboardingToken.ClassID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	school, err := h.schoolService.GetSchool(c.Request.Context(), onboardingToken.SchoolID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"valid":        true,
		"role":         onboardingToken.Role,
		"student_name": student.FirstName + " " + student.LastName,
		"class_name":   class.Name,
		"school_name":  school.Name,
		"expires_at":   onboardingToken.ExpiresAt,
	})
}

// RedeemOnboardingToken redeems a token and creates parent account
// POST /api/v1/onboarding/redeem
func (h *SchoolHandlers) RedeemOnboardingToken(c *gin.Context) {
	userID, exists := c.Get("user_id")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "user not authenticated"})
		return
	}

	var req struct {
		Token string `json:"token" binding:"required"`
	}

	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	err := h.schoolService.RedeemOnboardingToken(c.Request.Context(), req.Token, userID.(uuid.UUID))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "token redeemed successfully"})
}

// ========================================
// Register Routes
// ========================================

// RegisterRoutes registers all school-related routes
func (h *SchoolHandlers) RegisterRoutes(r *gin.RouterGroup, authMiddleware gin.HandlerFunc) {
	// Public routes (for onboarding)
	r.GET("/onboarding/validate", h.ValidateOnboardingToken)

	// Protected routes
	protected := r.Group("")
	protected.Use(authMiddleware)

	// Schools
	protected.POST("/schools", h.CreateSchool)
	protected.GET("/schools", h.ListSchools)
	protected.GET("/schools/:id", h.GetSchool)
	protected.POST("/schools/:id/years", h.CreateSchoolYear)
	protected.PUT("/schools/:id/years/:yearId/current", h.SetCurrentSchoolYear)
	protected.POST("/schools/:id/classes", h.CreateClass)
	protected.GET("/schools/:id/classes", h.ListClasses)
	protected.POST("/schools/:id/students", h.CreateStudent)
	protected.POST("/schools/:id/subjects", h.CreateSubject)
	protected.GET("/schools/:id/subjects", h.ListSubjects)

	// Classes
	protected.GET("/classes/:id", h.GetClass)
	protected.GET("/classes/:id/students", h.ListStudentsByClass)
	protected.GET("/classes/:id/attendance", h.GetClassAttendance)
	protected.POST("/classes/:id/attendance", h.RecordBulkAttendance)
	protected.GET("/classes/:id/absence/pending", h.GetPendingAbsenceReports)
	protected.GET("/classes/:id/grades/:subjectId", h.GetClassGrades)
	protected.GET("/classes/:id/grades/:subjectId/stats", h.GetGradeStatistics)

	// Students
	protected.GET("/students/:id", h.GetStudent)
	protected.GET("/students/:id/attendance", h.GetStudentAttendance)
	protected.GET("/students/:id/grades", h.GetStudentGrades)

	// Attendance & Absence
	protected.POST("/attendance", h.RecordAttendance)
	protected.POST("/absence/report", h.ReportAbsence)
	protected.PUT("/absence/:id/confirm", h.ConfirmAbsence)

	// Grades
	protected.POST("/grades", h.CreateGrade)

	// Onboarding
	protected.POST("/onboarding/tokens", h.GenerateOnboardingToken)
	protected.POST("/onboarding/redeem", h.RedeemOnboardingToken)
}
