package handlers

import (
	"net/http"
	"strconv"

	"github.com/breakpilot/school-service/internal/models"
	"github.com/gin-gonic/gin"
)

// GetClassGrades returns grades for a class
func (h *Handler) GetClassGrades(c *gin.Context) {
	classID := c.Param("classId")
	semesterStr := c.DefaultQuery("semester", "1")

	semester, err := strconv.Atoi(semesterStr)
	if err != nil || semester < 1 || semester > 2 {
		semester = 1
	}

	grades, err := h.gradeService.GetGradeOverview(c.Request.Context(), classID, semester)
	if err != nil {
		respondError(c, http.StatusInternalServerError, "Failed to get grades: "+err.Error())
		return
	}

	respondSuccess(c, grades)
}

// GetStudentGrades returns all grades for a student
func (h *Handler) GetStudentGrades(c *gin.Context) {
	studentID := c.Param("studentId")

	grades, err := h.gradeService.GetStudentGrades(c.Request.Context(), studentID)
	if err != nil {
		respondError(c, http.StatusInternalServerError, "Failed to get grades: "+err.Error())
		return
	}

	respondSuccess(c, grades)
}

// UpdateOralGrade updates the oral grade for a student
func (h *Handler) UpdateOralGrade(c *gin.Context) {
	studentID := c.Param("studentId")
	subjectID := c.Param("subjectId")

	var req models.UpdateOralGradeRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		respondError(c, http.StatusBadRequest, "Invalid request: "+err.Error())
		return
	}

	grade, err := h.gradeService.UpdateOralGrade(c.Request.Context(), studentID, subjectID, &req)
	if err != nil {
		respondError(c, http.StatusInternalServerError, "Failed to update oral grade: "+err.Error())
		return
	}

	respondSuccess(c, grade)
}

// CalculateFinalGrades calculates final grades for a class
func (h *Handler) CalculateFinalGrades(c *gin.Context) {
	var req struct {
		ClassID  string `json:"class_id" binding:"required"`
		Semester int    `json:"semester" binding:"required,min=1,max=2"`
	}

	if err := c.ShouldBindJSON(&req); err != nil {
		respondError(c, http.StatusBadRequest, "Invalid request: "+err.Error())
		return
	}

	if err := h.gradeService.CalculateFinalGrades(c.Request.Context(), req.ClassID, req.Semester); err != nil {
		respondError(c, http.StatusInternalServerError, "Failed to calculate grades: "+err.Error())
		return
	}

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

// TransferApprovedGrades transfers approved exam results to grade overview
func (h *Handler) TransferApprovedGrades(c *gin.Context) {
	teacherID := getUserID(c)
	if teacherID == "" {
		respondError(c, http.StatusUnauthorized, "User not authenticated")
		return
	}

	if err := h.gradeService.TransferApprovedGrades(c.Request.Context(), teacherID); err != nil {
		respondError(c, http.StatusInternalServerError, "Failed to transfer grades: "+err.Error())
		return
	}

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

// LockFinalGrade locks a final grade
func (h *Handler) LockFinalGrade(c *gin.Context) {
	studentID := c.Param("studentId")
	subjectID := c.Param("subjectId")
	semesterStr := c.DefaultQuery("semester", "1")

	semester, err := strconv.Atoi(semesterStr)
	if err != nil || semester < 1 || semester > 2 {
		semester = 1
	}

	if err := h.gradeService.LockFinalGrade(c.Request.Context(), studentID, subjectID, semester); err != nil {
		respondError(c, http.StatusInternalServerError, "Failed to lock grade: "+err.Error())
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "Grade locked"})
}

// UpdateGradeWeights updates the grade weights
func (h *Handler) UpdateGradeWeights(c *gin.Context) {
	studentID := c.Param("studentId")
	subjectID := c.Param("subjectId")

	var req struct {
		WrittenWeight int `json:"written_weight" binding:"required,min=0,max=100"`
		OralWeight    int `json:"oral_weight" binding:"required,min=0,max=100"`
	}

	if err := c.ShouldBindJSON(&req); err != nil {
		respondError(c, http.StatusBadRequest, "Invalid request: "+err.Error())
		return
	}

	if req.WrittenWeight+req.OralWeight != 100 {
		respondError(c, http.StatusBadRequest, "Weights must sum to 100")
		return
	}

	if err := h.gradeService.UpdateGradeWeights(c.Request.Context(), studentID, subjectID, req.WrittenWeight, req.OralWeight); err != nil {
		respondError(c, http.StatusInternalServerError, "Failed to update weights: "+err.Error())
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "Weights updated"})
}

// =============================================
// STATISTICS ENDPOINTS
// =============================================

// GetClassStatistics returns grade statistics for a class
// GET /api/v1/school/statistics/:classId
func (h *Handler) GetClassStatistics(c *gin.Context) {
	classID := c.Param("classId")
	semesterStr := c.DefaultQuery("semester", "0") // 0 = both semesters

	semester, _ := strconv.Atoi(semesterStr)

	stats, err := h.gradeService.GetClassStatistics(c.Request.Context(), classID, semester)
	if err != nil {
		respondError(c, http.StatusInternalServerError, "Failed to get statistics: "+err.Error())
		return
	}

	respondSuccess(c, stats)
}

// GetSubjectStatistics returns grade statistics for a specific subject in a class
// GET /api/v1/school/statistics/:classId/subject/:subjectId
func (h *Handler) GetSubjectStatistics(c *gin.Context) {
	classID := c.Param("classId")
	subjectID := c.Param("subjectId")
	semesterStr := c.DefaultQuery("semester", "0")

	semester, _ := strconv.Atoi(semesterStr)

	stats, err := h.gradeService.GetSubjectStatistics(c.Request.Context(), classID, subjectID, semester)
	if err != nil {
		respondError(c, http.StatusInternalServerError, "Failed to get statistics: "+err.Error())
		return
	}

	respondSuccess(c, stats)
}

// GetStudentStatistics returns grade statistics for a specific student
// GET /api/v1/school/statistics/student/:studentId
func (h *Handler) GetStudentStatistics(c *gin.Context) {
	studentID := c.Param("studentId")

	stats, err := h.gradeService.GetStudentStatistics(c.Request.Context(), studentID)
	if err != nil {
		respondError(c, http.StatusInternalServerError, "Failed to get statistics: "+err.Error())
		return
	}

	respondSuccess(c, stats)
}

// GetNotenspiegel returns the grade distribution for a class or exam
// GET /api/v1/school/statistics/:classId/notenspiegel
func (h *Handler) GetNotenspiegel(c *gin.Context) {
	classID := c.Param("classId")
	subjectID := c.Query("subject_id")
	examID := c.Query("exam_id")
	semesterStr := c.DefaultQuery("semester", "0")

	semester, _ := strconv.Atoi(semesterStr)

	notenspiegel, err := h.gradeService.GetNotenspiegel(c.Request.Context(), classID, subjectID, examID, semester)
	if err != nil {
		respondError(c, http.StatusInternalServerError, "Failed to get Notenspiegel: "+err.Error())
		return
	}

	respondSuccess(c, notenspiegel)
}
