package controllers

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"
	"time"

	"learnsteam/learsteam-quiz-api/internal/models"
	"learnsteam/learsteam-quiz-api/internal/services"

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

type ExamController interface {
	List(*gin.Context)
	Find(*gin.Context)
	Create(*gin.Context)
	Update(*gin.Context)
	Patch(*gin.Context)
}

type examController struct {
	service        services.ExamService
	userService    services.UserService
	programService services.ProgramService
}

func NewExamController(service services.ExamService, userService services.UserService, programService services.ProgramService) ExamController {
	return &examController{
		service:        service,
		userService:    userService,
		programService: programService,
	}
}

// Exam List
//
// @Summary			응시 목록 가져오기
// @Description	응시 목록을 가져옵니다.
// @Tags 				Exam
//
// @Accept json
// @Produce json
//
// @Param q query string false "검색어"
// @Param page query int false "페이지"
// @Param limit query int false "페이지 사이즈"
//
// @Success 200 {object} models.ExamListResponse
// @Router /exam  [get]
func (controller *examController) List(c *gin.Context) {
	q := c.DefaultQuery("q", "")
	page, err := strconv.Atoi(c.DefaultQuery("page", "1"))
	if err != nil {
		fmt.Println("error : page")
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	limit, err := strconv.Atoi(c.DefaultQuery("limit", "10"))
	if err != nil {
		fmt.Println("error : limit")
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	result, err := controller.service.List(q, page, limit)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	totalNumber, err := controller.service.Total(q)
	if err != nil {
		fmt.Println("error : list")
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	totalPage := int64(totalNumber/int64(limit) + 1)

	response := models.ExamListResponse{
		Data:      *result,
		Total:     totalNumber,
		Page:      page,
		TotalPage: totalPage,
		PageSize:  limit,
	}

	c.JSON(http.StatusOK, response)
}

// Get exam
//
// @Summary 		응시(시험) 정보 가져오기
// @Description	ID로 응시 정보를 가져옵니다.
// @Tags 				Exam
//
// @Accept json
// @Produce json
//
// @Param id path string true "응시 ID"
//
// @Success 200 {object} models.ExamResponse
// @Router /exam/{id} [get]
func (controller *examController) Find(c *gin.Context) {
	id := c.Param("id")

	result, err := controller.service.Find(id)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, result)
}

// Create Exam
//
// @Summary 		응시 매칭 생성
// @Description	응시 매칭을 만듭니다.
// @Tags 				Exam
//
// @Accept json
// @Produce json
//
// @Param examBody body models.ExamRequest true "Exam Body"
//
// @Success 200 {object} models.ExamResponse
// @Router /exam [post]
func (controller *examController) Create(c *gin.Context) {
	var request models.ExamRequest
	if err := c.ShouldBindJSON(&request); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	fmt.Println("users", request.Users)

	program, err := controller.programService.Find(request.ProgramID)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	var users []string
	err = json.Unmarshal(request.Users, &users)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	count := 0
	for _, user_id := range users {
		user, err := controller.userService.Find(user_id)
		if err != nil {
			continue
		}

		exam := &models.Exam{
			ID:        uuid.NewString(),
			ProgramID: program.ID,
			UserID:    user_id,
			Subject:   program.Subject,
			Program:   program.Course,
			Name:      user.Name,
			Score:     0,
			Total:     5,
			Status:    "ready",
		}

		_, err = controller.service.Create(exam)
		if err != nil {
			continue
		}
		count += 1
	}

	c.JSON(http.StatusOK, gin.H{"count": count})
}

// Update Exam
//
// @Summary			퀴즈 프로그램 수정
// @Description 퀴즈 프로그램을 수정합니다.
// @Tags 				Exam
//
// @Accept json
// @Produce json
//
// @Param examUpdateBody body models.ExamUpdateRequest true "Exam Update Body"
//
// @Success 200 {object} models.ExamResponse
// @Router /exam [put]
func (controller *examController) Update(c *gin.Context) {
	id := c.Param("id")
	var request models.ExamUpdateRequest
	if err := c.ShouldBindJSON(&request); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	fmt.Println("request", request)
	exam, err := controller.service.Find(id)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	exam.ProgramID = request.ProgramID
	exam.UserID = request.UserID
	exam.Subject = request.Subject
	exam.Program = request.Program
	exam.Name = request.Name
	exam.Status = request.Status
	exam.Score = request.Score
	exam.Total = request.Total

	if request.StartAt != "" {
		fmt.Println("request.StartAt", request.StartAt)
		start_at, err := time.Parse("2006-01-02T15:04:05-07:00", request.StartAt)
		if err == nil {
			exam.StartAt = &start_at
		}
		fmt.Println("start_at", start_at)
	}

	if request.EndAt != "" {
		fmt.Println("request.EndAt", request.EndAt)
		end_at, err := time.Parse("2006-01-02T15:04:05-07:00", request.EndAt)
		if err == nil {
			exam.EndAt = &end_at
		}
		fmt.Println("end_at", end_at)
	}
	fmt.Println("exam", exam)
	result, err := controller.service.Update(exam)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	fmt.Println("result", result)
	c.JSON(http.StatusOK, result)
}

// Patch Exam
//
// @Summary			퀴즈 프로그램 정보 변경
// @Description 퀴즈 프로그램 정보를 변경합니다.
// @Tags 				Exam
//
// @Accept json
// @Produce json
//
// @Param examPatchBody body models.ExamPatchRequest true "Exam Patch Body (변경할 필드만 입력)"
//
// @Success 200 {object} models.ExamResponse
// @Router /exam [patch]
func (controller *examController) Patch(c *gin.Context) {
	id := c.Param("id")
	var request models.ExamPatchRequest
	if err := c.ShouldBindJSON(&request); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	fmt.Println("request", request)
	exam, err := controller.service.Find(id)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	if request.Status != "" {
		exam.Status = request.Status
	}

	if request.StartAt != "" {
		fmt.Println("request.StartAt", request.StartAt)
		start_at, err := time.Parse("2006-01-02T15:04:05-07:00", request.StartAt)
		if err == nil {
			exam.StartAt = &start_at
		}
		fmt.Println("start_at", start_at)
	}

	if request.EndAt != "" {
		fmt.Println("request.EndAt", request.EndAt)
		end_at, err := time.Parse("2006-01-02T15:04:05-07:00", request.EndAt)
		if err == nil {
			exam.EndAt = &end_at
		}
		fmt.Println("end_at", end_at)
	}
	fmt.Println("exam", exam)
	result, err := controller.service.Update(exam)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	fmt.Println("result", result)
	c.JSON(http.StatusOK, result)
}
