package restricted

import (
	"strconv"

	"git.ma-al.com/goc_daniel/b2b/app/service/cartsService"
	"git.ma-al.com/goc_daniel/b2b/app/utils/i18n"
	"git.ma-al.com/goc_daniel/b2b/app/utils/nullable"
	"git.ma-al.com/goc_daniel/b2b/app/utils/response"
	"git.ma-al.com/goc_daniel/b2b/app/utils/responseErrors"
	"github.com/gofiber/fiber/v3"
)

// CartsHandler handles endpoints that modify carts.
type CartsHandler struct {
	cartsService *cartsService.CartsService
}

// CartsHandler creates a new CartsHandler instance
func NewCartsHandler() *CartsHandler {
	cartsService := cartsService.New()
	return &CartsHandler{
		cartsService: cartsService,
	}
}

func CartsHandlerRoutes(r fiber.Router) fiber.Router {
	handler := NewCartsHandler()

	r.Get("/add-new-cart", handler.AddNewCart)
	r.Get("/change-cart-name", handler.ChangeCartName)
	r.Get("/retrieve-carts-info", handler.RetrieveCartsInfo)
	r.Get("/retrieve-cart", handler.RetrieveCart)
	r.Get("/add-product-to-cart", handler.AddProduct)

	return r
}

func (h *CartsHandler) AddNewCart(c fiber.Ctx) error {
	userID, ok := c.Locals("userID").(uint)
	if !ok {
		return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrInvalidBody)).
			JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrInvalidBody)))
	}

	new_cart, err := h.cartsService.CreateNewCart(userID)
	if err != nil {
		return c.Status(responseErrors.GetErrorStatus(err)).
			JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, err)))
	}

	return c.JSON(response.Make(&new_cart, 0, i18n.T_(c, response.Message_OK)))
}

func (h *CartsHandler) ChangeCartName(c fiber.Ctx) error {
	userID, ok := c.Locals("userID").(uint)
	if !ok {
		return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrInvalidBody)).
			JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrInvalidBody)))
	}

	new_name := c.Query("new_name")

	cart_id_attribute := c.Query("cart_id")
	cart_id, err := strconv.Atoi(cart_id_attribute)
	if err != nil {
		return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadAttribute)).
			JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrBadAttribute)))
	}

	err = h.cartsService.UpdateCartName(userID, uint(cart_id), new_name)
	if err != nil {
		return c.Status(responseErrors.GetErrorStatus(err)).
			JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, err)))
	}

	return c.JSON(response.Make(nullable.GetNil(""), 0, i18n.T_(c, response.Message_OK)))
}

func (h *CartsHandler) RetrieveCartsInfo(c fiber.Ctx) error {
	userID, ok := c.Locals("userID").(uint)
	if !ok {
		return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrInvalidBody)).
			JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrInvalidBody)))
	}

	carts_info, err := h.cartsService.RetrieveCartsInfo(userID)
	if err != nil {
		return c.Status(responseErrors.GetErrorStatus(err)).
			JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, err)))
	}

	return c.JSON(response.Make(&carts_info, 0, i18n.T_(c, response.Message_OK)))
}

func (h *CartsHandler) RetrieveCart(c fiber.Ctx) error {
	userID, ok := c.Locals("userID").(uint)
	if !ok {
		return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrInvalidBody)).
			JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrInvalidBody)))
	}

	cart_id_attribute := c.Query("cart_id")
	cart_id, err := strconv.Atoi(cart_id_attribute)
	if err != nil {
		return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadAttribute)).
			JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrBadAttribute)))
	}

	cart, err := h.cartsService.RetrieveCart(userID, uint(cart_id))
	if err != nil {
		return c.Status(responseErrors.GetErrorStatus(err)).
			JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, err)))
	}

	return c.JSON(response.Make(cart, 0, i18n.T_(c, response.Message_OK)))
}

func (h *CartsHandler) AddProduct(c fiber.Ctx) error {
	userID, ok := c.Locals("userID").(uint)
	if !ok {
		return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrInvalidBody)).
			JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrInvalidBody)))
	}

	cart_id_attribute := c.Query("cart_id")
	cart_id, err := strconv.Atoi(cart_id_attribute)
	if err != nil {
		return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadAttribute)).
			JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrBadAttribute)))
	}

	product_id_attribute := c.Query("product_id")
	product_id, err := strconv.Atoi(product_id_attribute)
	if err != nil {
		return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadAttribute)).
			JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrBadAttribute)))
	}

	product_attribute_id_attribute := c.Query("product_attribute_id")
	var product_attribute_id *uint
	if product_attribute_id_attribute == "" {
		product_attribute_id = nil
	} else {
		val, err := strconv.Atoi(product_attribute_id_attribute)
		if err != nil {
			return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadAttribute)).
				JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrBadAttribute)))
		}
		uval := uint(val)
		product_attribute_id = &uval
	}

	amount_attribute := c.Query("amount")
	amount, err := strconv.Atoi(amount_attribute)
	if err != nil {
		return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadAttribute)).
			JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrBadAttribute)))
	}

	err = h.cartsService.AddProduct(userID, uint(cart_id), uint(product_id), product_attribute_id, uint(amount))
	if err != nil {
		return c.Status(responseErrors.GetErrorStatus(err)).
			JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, err)))
	}

	return c.JSON(response.Make(nullable.GetNil(""), 0, i18n.T_(c, response.Message_OK)))
}
