package controller

import (
	"math"
	"strconv"
	"strings"

	"github.com/gofiber/fiber/v2"
	common "gitlab.com/mbugroup/lti-api.git/internal/common/service"
	"gitlab.com/mbugroup/lti-api.git/internal/modules/approvals/dto"
	validation "gitlab.com/mbugroup/lti-api.git/internal/modules/approvals/validations"
	"gitlab.com/mbugroup/lti-api.git/internal/response"
)

type ApprovalController struct {
	ApprovalService common.ApprovalService
}

func NewApprovalController(approvalService common.ApprovalService) *ApprovalController {
	return &ApprovalController{
		ApprovalService: approvalService,
	}
}

func (u *ApprovalController) GetAll(c *fiber.Ctx) error {
	moduleName := strings.TrimSpace(c.Query("module_name", ""))
	if moduleName == "" {
		return fiber.NewError(fiber.StatusBadRequest, "`module_name` is required")
	}

	moduleIDParam := strings.TrimSpace(c.Query("module_id", ""))
	var moduleID *uint
	if moduleIDParam != "" {
		value, err := strconv.ParseUint(moduleIDParam, 10, 64)
		if err != nil || value == 0 {
			return fiber.NewError(fiber.StatusBadRequest, "module_id must be a positive integer")
		}
		id := uint(value)
		moduleID = &id
	}

	groupByStep := c.QueryBool("group_step_number", false)

	page := c.QueryInt("page", 1)
	limit := c.QueryInt("limit", 10)
	search := strings.TrimSpace(c.Query("search", ""))
	orderByDate := strings.TrimSpace(c.Query("order_by_date", ""))
	if orderByDate == "" {
		orderByDate = "DESC"
	} else {
		orderByDate = strings.ToUpper(orderByDate)
		if orderByDate != "ASC" && orderByDate != "DESC" {
			return fiber.NewError(fiber.StatusBadRequest, "order_by_date must be either ASC or DESC")
		}
	}

	query := &validation.Query{
		ModuleName:  moduleName,
		ModuleId:    moduleID,
		GroupByStep: groupByStep,
		Page:        page,
		Limit:       limit,
		Search:      search,
		OrderByDate: orderByDate,
	}

	records, totalResults, err := u.ApprovalService.List(
		c.Context(),
		query.ModuleName,
		query.ModuleId,
		query.Page,
		query.Limit,
		query.Search,
		query.OrderByDate,
	)
	if err != nil {
		return err
	}

	if query.GroupByStep {
		data := dto.ToApprovalGroupDTOs(records)
		return c.Status(fiber.StatusOK).
			JSON(response.SuccessWithPaginate[dto.ApprovalGroupDTO]{
				Code:    fiber.StatusOK,
				Status:  "success",
				Message: "Get All approvals successfully",
				Meta: response.Meta{
					Page:         query.Page,
					Limit:        query.Limit,
					TotalPages:   int64(math.Ceil(float64(totalResults) / float64(query.Limit))),
					TotalResults: totalResults,
				},
				Data: data,
			})
	}

	flat := dto.ToApprovalDTOs(records)
	return c.Status(fiber.StatusOK).
		JSON(response.SuccessWithPaginate[dto.ApprovalRelationDTO]{
			Code:    fiber.StatusOK,
			Status:  "success",
			Message: "Get All approvals successfully",
			Meta: response.Meta{
				Page:         query.Page,
				Limit:        query.Limit,
				TotalPages:   int64(math.Ceil(float64(totalResults) / float64(query.Limit))),
				TotalResults: totalResults,
			},
			Data: flat,
		})
}
