package handlers

import (
	"fmt"
	"strconv"
	"strings"
	"time"

	internalDb "server/internal/db"
	"server/internal/models"

	"github.com/gofiber/fiber/v2"
	"gorm.io/gorm"
)

type studentShiftItem struct {
	Period           int    `json:"period"`
	CourseName       string `json:"courseName"`
	StartTime        string `json:"startTime"`
	EndTime          string `json:"endTime"`
	IsActiveNow      bool   `json:"isActiveNow"`
	OnlineSeconds    int    `json:"onlineSeconds"`
	OfflineSeconds   int    `json:"offlineSeconds"`
	AttendanceStatus int    `json:"attendanceStatus"`
	AttendanceLabel  string `json:"attendanceLabel"`
}

// GET /api/student/status — trạng thái giám sát, lớp/ca hiện tại, tích lũy & điểm danh hôm nay
func GetStudentStatusHandler(db *gorm.DB) fiber.Handler {
	return func(c *fiber.Ctx) error {
		studentID, err := strconv.ParseInt(c.Query("studentRkId", "0"), 10, 64)
		if err != nil || studentID <= 0 {
			return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "studentRkId is required"})
		}

		now := time.Now()
		today := now.Format("2006-01-02")
		dayIdx := weekdayIndex(now)
		currMin := now.Hour()*60 + now.Minute()

		classID, activePeriod := internalDb.FindActiveClassAndPeriodForStudent(db, studentID)
		if classID <= 0 {
			var link models.ClassStudent
			if err := db.Where("student_rk_id = ?", studentID).First(&link).Error; err == nil {
				classID = link.ClassRkID
			}
		}

		className, classCode := "", ""
		if classID > 0 {
			var cl models.Class
			if err := db.Where("rk_id = ?", classID).First(&cl).Error; err == nil {
				className = cl.Name
				classCode = cl.ClassCode
			}
		}

		var todaySchedules []models.ClassSchedule
		if classID > 0 {
			_ = db.Where("class_rk_id = ? AND day_of_week = ? AND is_active = ?", classID, dayIdx, true).
				Order("period asc, start_time asc").Find(&todaySchedules).Error
		}

		inScheduleNow := false
		currentPeriod := 0
		currentCourse, currentStart, currentEnd := "", "", ""
		for _, s := range todaySchedules {
			startMin := parseTimeMinutes(s.StartTime)
			endMin := parseTimeMinutes(s.EndTime)
			if currMin >= startMin && currMin <= endMin {
				inScheduleNow = true
				currentPeriod = s.Period
				if currentPeriod < 1 {
					currentPeriod = 1
				}
				currentCourse = s.CourseName
				currentStart = s.StartTime
				currentEnd = s.EndTime
				break
			}
		}
		if !inScheduleNow && activePeriod > 0 {
			currentPeriod = activePeriod
		}

		hasApps := false
		keywords := ""
		if classID > 0 {
			var appConfig models.ClassAllowedApp
			if err := db.Where("class_rk_id = ?", classID).First(&appConfig).Error; err == nil {
				keywords = strings.TrimSpace(appConfig.Keywords)
				hasApps = keywords != ""
			}
		}

		monitorMode := "outside_schedule"
		monitorLabel := "Ngoài giờ học"
		if classID <= 0 {
			monitorMode = "not_configured"
			monitorLabel = "Chưa xác định được lớp học"
		} else if !hasApps {
			monitorMode = "not_configured"
			monitorLabel = "Lớp chưa cấu hình ứng dụng được phép"
		} else if inScheduleNow {
			monitorMode = "learning"
			if currentCourse != "" {
				monitorLabel = fmt.Sprintf("Ca %d — %s (%s–%s)", currentPeriod, currentCourse, currentStart, currentEnd)
			} else {
				monitorLabel = fmt.Sprintf("Đang giám sát — Ca %d", currentPeriod)
			}
		}
		// monitorMode = "exam" — xử lý ở nhánh FindActiveExamForStudent phía trên

		sessionMap := map[int]models.StudentSession{}
		attMap := map[int]models.AttendanceResult{}
		if classID > 0 {
			var sessions []models.StudentSession
			_ = db.Where("student_rk_id = ? AND class_rk_id = ? AND session_date = ?", studentID, classID, today).Find(&sessions).Error
			for _, s := range sessions {
				p := s.Period
				if p < 1 {
					p = 1
				}
				sessionMap[p] = s
			}
			var attendances []models.AttendanceResult
			_ = db.Where("student_rk_id = ? AND class_rk_id = ? AND session_date = ?", studentID, classID, today).Find(&attendances).Error
			for _, a := range attendances {
				p := a.Period
				if p < 1 {
					p = 1
				}
				attMap[p] = a
			}
		}

		shifts := make([]studentShiftItem, 0, len(todaySchedules))
		for _, sch := range todaySchedules {
			period := sch.Period
			if period < 1 {
				period = 1
			}
			sess := sessionMap[period]
			att := attMap[period]
			startMin := parseTimeMinutes(sch.StartTime)
			endMin := parseTimeMinutes(sch.EndTime)
			isActiveNow := currMin >= startMin && currMin <= endMin

			attStatus := -1
			attLabel := "Chưa tính"
			if att.ID > 0 {
				attStatus = att.Status
				attLabel = att.StatusLabel
				if attLabel == "" {
					attLabel = attendanceLabelFallback(att.Status)
				}
			}

			shifts = append(shifts, studentShiftItem{
				Period:           period,
				CourseName:       sch.CourseName,
				StartTime:        sch.StartTime,
				EndTime:          sch.EndTime,
				IsActiveNow:      isActiveNow,
				OnlineSeconds:    sess.OnlineSeconds,
				OfflineSeconds:   sess.OfflineSeconds,
				AttendanceStatus: attStatus,
				AttendanceLabel:  attLabel,
			})
		}

		// Ưu tiên phòng thi nếu sinh viên đang trong khung giờ thi
		if examInfo := internalDb.FindActiveExamForStudent(db, studentID); examInfo != nil {
			examKeywords := strings.TrimSpace(examInfo.Room.AllowedApps)
			if examKeywords == "" {
				examKeywords = defaultExamAllowedApps
			}
			paperSent := examInfo.Enrollment.PaperSentAt != nil
			var subCount int64
			_ = db.Model(&models.ExamSubmission{}).Where("exam_room_id = ? AND student_rk_id = ?", examInfo.Room.ID, studentID).Count(&subCount).Error
			examPayload := fiber.Map{
				"examRoomId": examInfo.Room.ID,
				"examName":   examInfo.Room.Name,
				"startTime":  examInfo.Room.StartTime,
				"endTime":    examInfo.Room.EndTime,
				"quizUrl":    examInfo.Room.QuizURL,
				"paperSent":  paperSent,
				"submitted":  subCount > 0,
			}
			if paperSent && examInfo.Paper != nil {
				examPayload["paperId"] = examInfo.Paper.ID
				examPayload["paperTitle"] = examInfo.Paper.Title
			}
			return c.JSON(fiber.Map{
				"sessionDate":       today,
				"monitorMode":       "exam",
				"monitorLabel":      fmt.Sprintf("Phòng thi: %s", examInfo.Room.Name),
				"classRkId":         classID,
				"className":         className,
				"classCode":         classCode,
				"currentPeriod":     0,
				"currentCourseName": "",
				"currentShiftStart": "",
				"currentShiftEnd":   "",
				"inScheduleNow":     false,
				"blockerActive":     examKeywords != "",
				"allowedKeywords":   examKeywords,
				"shifts":            shifts,
				"exam":              examPayload,
			})
		}

		return c.JSON(fiber.Map{
			"sessionDate":       today,
			"monitorMode":       monitorMode,
			"monitorLabel":      monitorLabel,
			"classRkId":         classID,
			"className":         className,
			"classCode":         classCode,
			"currentPeriod":     currentPeriod,
			"currentCourseName": currentCourse,
			"currentShiftStart": currentStart,
			"currentShiftEnd":   currentEnd,
			"inScheduleNow":     inScheduleNow,
			"blockerActive":     hasApps && inScheduleNow,
			"allowedKeywords":   keywords,
			"shifts":            shifts,
		})
	}
}

func weekdayIndex(t time.Time) int {
	wd := t.Weekday()
	if wd == time.Sunday {
		return 6
	}
	return int(wd) - 1
}

func attendanceLabelFallback(status int) string {
	switch status {
	case 1:
		return "Nghỉ có phép"
	case 2:
		return "Nghỉ nửa buổi"
	case 3:
		return "Đi học muộn"
	case 4:
		return "Đi học đầy đủ"
	default:
		return "Nghỉ không phép"
	}
}
