package classrooms

import (
	"boostai-backend/internal/handlers/api/shared"
	"boostai-backend/internal/http/params"
	"boostai-backend/internal/http/respond"
	authmw "boostai-backend/internal/middleware"
	"boostai-backend/internal/sqlc"
	"strings"
	"time"

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

type Handler struct {
	queries *sqlc.Queries
}

type ClassroomResponse struct {
	ID          int64      `json:"id"`
	TeacherID   int64      `json:"teacher_id"`
	Name        string     `json:"name"`
	Code        *string    `json:"code,omitempty"`
	Description *string    `json:"description,omitempty"`
	CreatedAt   *time.Time `json:"created_at,omitempty"`
	UpdatedAt   *time.Time `json:"updated_at,omitempty"`
}

type StudentResponse struct {
	ID        int64      `json:"id"`
	Email     string     `json:"email"`
	Role      string     `json:"role"`
	FullName  string     `json:"full_name"`
	IsActive  bool       `json:"is_active"`
	CreatedAt *time.Time `json:"created_at,omitempty"`
	UpdatedAt *time.Time `json:"updated_at,omitempty"`
}

type createClassroomRequest struct {
	TeacherID   int64   `json:"teacher_id"`
	Name        string  `json:"name"`
	Code        *string `json:"code"`
	Description *string `json:"description"`
}

type addStudentToClassroomRequest struct {
	StudentID int64 `json:"student_id"`
}

func NewHandler(queries *sqlc.Queries) *Handler {
	return &Handler{queries: queries}
}

func (h *Handler) ListClassroomsByTeacher(c *fiber.Ctx) error {
	teacherID, err := params.Int64PathParam(c, "teacherId")
	if err != nil {
		return err
	}

	ctx, cancel := shared.WithTimeout()
	defer cancel()

	classrooms, err := h.queries.ListClassroomsByTeacher(ctx, teacherID)
	if err != nil {
		return respond.DatabaseError(c, err)
	}

	items := make([]ClassroomResponse, 0, len(classrooms))
	for _, classroom := range classrooms {
		items = append(items, mapClassroom(classroom))
	}

	return c.JSON(shared.ListResponse[ClassroomResponse]{Data: items})
}

func (h *Handler) ListStudentsForClassroom(c *fiber.Ctx) error {
	classroomID, err := params.Int64PathParam(c, "classroomId")
	if err != nil {
		return err
	}

	ctx, cancel := shared.WithTimeout()
	defer cancel()

	students, err := h.queries.ListStudentsForClassroom(ctx, classroomID)
	if err != nil {
		return respond.DatabaseError(c, err)
	}

	items := make([]StudentResponse, 0, len(students))
	for _, student := range students {
		items = append(items, mapStudent(student))
	}

	return c.JSON(shared.ListResponse[StudentResponse]{Data: items})
}

func (h *Handler) CreateClassroom(c *fiber.Ctx) error {
	var req createClassroomRequest
	if err := c.BodyParser(&req); err != nil {
		return respond.Error(c, fiber.StatusBadRequest, "invalid_request", "Unable to parse request body")
	}

	teacherID := authmw.CurrentUserID(c)
	if teacherID == 0 || strings.TrimSpace(req.Name) == "" {
		return respond.Error(c, fiber.StatusBadRequest, "invalid_request", "teacher authentication and name are required")
	}

	ctx, cancel := shared.WithTimeout()
	defer cancel()

	classroom, err := h.queries.CreateClassroom(ctx, sqlc.CreateClassroomParams{
		TeacherID:   teacherID,
		Name:        strings.TrimSpace(req.Name),
		Code:        shared.NullableText(req.Code),
		Description: shared.NullableText(req.Description),
	})
	if err != nil {
		return respond.DatabaseError(c, err)
	}

	return c.Status(fiber.StatusCreated).JSON(mapClassroom(classroom))
}

func (h *Handler) AddStudentToClassroom(c *fiber.Ctx) error {
	classroomID, err := params.Int64PathParam(c, "classroomId")
	if err != nil {
		return err
	}

	var req addStudentToClassroomRequest
	if err := c.BodyParser(&req); err != nil {
		return respond.Error(c, fiber.StatusBadRequest, "invalid_request", "Unable to parse request body")
	}

	if req.StudentID == 0 {
		return respond.Error(c, fiber.StatusBadRequest, "invalid_request", "student_id is required")
	}

	ctx, cancel := shared.WithTimeout()
	defer cancel()

	err = h.queries.AddStudentToClassroom(ctx, sqlc.AddStudentToClassroomParams{
		ClassroomID: classroomID,
		StudentID:   req.StudentID,
	})
	if err != nil {
		return respond.DatabaseError(c, err)
	}

	return c.Status(fiber.StatusCreated).JSON(fiber.Map{
		"status":       "ok",
		"classroom_id": classroomID,
		"student_id":   req.StudentID,
	})
}

func mapClassroom(classroom sqlc.Classroom) ClassroomResponse {
	return ClassroomResponse{
		ID:          classroom.ID,
		TeacherID:   classroom.TeacherID,
		Name:        classroom.Name,
		Code:        shared.TextPointer(classroom.Code),
		Description: shared.TextPointer(classroom.Description),
		CreatedAt:   shared.TimePointer(classroom.CreatedAt),
		UpdatedAt:   shared.TimePointer(classroom.UpdatedAt),
	}
}

func mapStudent(user sqlc.User) StudentResponse {
	return StudentResponse{
		ID:        user.ID,
		Email:     user.Email,
		Role:      string(user.Role),
		FullName:  user.FullName,
		IsActive:  user.IsActive,
		CreatedAt: shared.TimePointer(user.CreatedAt),
		UpdatedAt: shared.TimePointer(user.UpdatedAt),
	}
}
