package controller

import (
	"math"
	"strconv"
	"strings"

	"gitlab.com/mbugroup/lti-api.git/internal/modules/master/warehouses/dto"
	service "gitlab.com/mbugroup/lti-api.git/internal/modules/master/warehouses/services"
	validation "gitlab.com/mbugroup/lti-api.git/internal/modules/master/warehouses/validations"
	"gitlab.com/mbugroup/lti-api.git/internal/response"
	"gitlab.com/mbugroup/lti-api.git/internal/utils"

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

type WarehouseController struct {
	WarehouseService service.WarehouseService
}

func NewWarehouseController(warehouseService service.WarehouseService) *WarehouseController {
	return &WarehouseController{
		WarehouseService: warehouseService,
	}
}

func (u *WarehouseController) GetAll(c *fiber.Ctx) error {
	excludeIDs, err := parseCommaSeparatedUint(c.Query("exclude_id", ""))
	if err != nil {
		return fiber.NewError(fiber.StatusBadRequest, err.Error())
	}

	query := &validation.Query{
		Page:                   c.QueryInt("page", 1),
		Limit:                  c.QueryInt("limit", 10),
		Search:                 c.Query("search", ""),
		AreaId:                 c.QueryInt("area_id", 0),
		LocationId:             c.QueryInt("location_id", 0),
		ActiveProjectFlockOnly: c.QueryBool("active_project_flock", false),
		TransferContext:        c.Query(utils.TransferContextKey, ""),
		ExcludeIDs:             excludeIDs,
	}

	if query.Page < 1 || query.Limit < 1 {
		return fiber.NewError(fiber.StatusBadRequest, "page and limit must be greater than 0")
	}

	result, totalResults, err := u.WarehouseService.GetAll(c, query)
	if err != nil {
		return err
	}

	return c.Status(fiber.StatusOK).
		JSON(response.SuccessWithPaginate[dto.WarehouseListDTO]{
			Code:    fiber.StatusOK,
			Status:  "success",
			Message: "Get all warehouses successfully",
			Meta: response.Meta{
				Page:         query.Page,
				Limit:        query.Limit,
				TotalPages:   int64(math.Ceil(float64(totalResults) / float64(query.Limit))),
				TotalResults: totalResults,
			},
			Data: dto.ToWarehouseListDTOs(result),
		})
}

func parseCommaSeparatedUint(raw string) ([]uint, error) {
	raw = strings.TrimSpace(raw)
	if raw == "" {
		return nil, nil
	}

	parts := strings.Split(raw, ",")
	out := make([]uint, 0, len(parts))
	for _, part := range parts {
		part = strings.TrimSpace(part)
		if part == "" {
			continue
		}
		value, err := strconv.ParseUint(part, 10, 64)
		if err != nil {
			return nil, fiber.NewError(fiber.StatusBadRequest, "invalid exclude_id")
		}
		out = append(out, uint(value))
	}
	return out, nil
}

func (u *WarehouseController) GetOne(c *fiber.Ctx) error {
	param := c.Params("id")

	id, err := strconv.Atoi(param)
	if err != nil {
		return fiber.NewError(fiber.StatusBadRequest, "Invalid Id")
	}

	result, err := u.WarehouseService.GetOne(c, uint(id))
	if err != nil {
		return err
	}

	return c.Status(fiber.StatusOK).
		JSON(response.Success{
			Code:    fiber.StatusOK,
			Status:  "success",
			Message: "Get warehouse successfully",
			Data:    dto.ToWarehouseListDTO(*result),
		})
}

func (u *WarehouseController) CreateOne(c *fiber.Ctx) error {
	req := new(validation.Create)

	if err := c.BodyParser(req); err != nil {
		return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
	}

	result, err := u.WarehouseService.CreateOne(c, req)
	if err != nil {
		return err
	}

	return c.Status(fiber.StatusCreated).
		JSON(response.Success{
			Code:    fiber.StatusCreated,
			Status:  "success",
			Message: "Create warehouse successfully",
			Data:    dto.ToWarehouseListDTO(*result),
		})
}

func (u *WarehouseController) UpdateOne(c *fiber.Ctx) error {
	req := new(validation.Update)
	param := c.Params("id")

	id, err := strconv.Atoi(param)
	if err != nil {
		return fiber.NewError(fiber.StatusBadRequest, "Invalid Id")
	}

	if err := c.BodyParser(req); err != nil {
		return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
	}

	result, err := u.WarehouseService.UpdateOne(c, req, uint(id))
	if err != nil {
		return err
	}

	return c.Status(fiber.StatusOK).
		JSON(response.Success{
			Code:    fiber.StatusOK,
			Status:  "success",
			Message: "Update warehouse successfully",
			Data:    dto.ToWarehouseListDTO(*result),
		})
}

func (u *WarehouseController) DeleteOne(c *fiber.Ctx) error {
	param := c.Params("id")

	id, err := strconv.Atoi(param)
	if err != nil {
		return fiber.NewError(fiber.StatusBadRequest, "Invalid Id")
	}

	if err := u.WarehouseService.DeleteOne(c, uint(id)); err != nil {
		return err
	}

	return c.Status(fiber.StatusOK).
		JSON(response.Common{
			Code:    fiber.StatusOK,
			Status:  "success",
			Message: "Delete warehouse successfully",
		})
}
