package restricted

import (
	"strconv"

	"git.ma-al.com/goc_daniel/b2b/app/delivery/middleware/perms"
	"git.ma-al.com/goc_daniel/b2b/app/model"
	"git.ma-al.com/goc_daniel/b2b/app/service/customerService"
	"git.ma-al.com/goc_daniel/b2b/app/utils/i18n"
	"git.ma-al.com/goc_daniel/b2b/app/utils/localeExtractor"
	"git.ma-al.com/goc_daniel/b2b/app/utils/nullable"
	"git.ma-al.com/goc_daniel/b2b/app/utils/query/query_params"
	"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"
)

type customerHandler struct {
	service *customerService.CustomerService
}

func NewCustomerHandler() *customerHandler {
	customerService := customerService.New()
	return &customerHandler{
		service: customerService,
	}
}

func CustomerHandlerRoutes(r fiber.Router) fiber.Router {
	handler := NewCustomerHandler()

	r.Get("", handler.customerData)
	r.Get("/list", handler.listCustomers)
	return r
}

func (h *customerHandler) customerData(fc fiber.Ctx) error {
	var customerId uint

	user, ok := localeExtractor.GetCustomer(fc)
	if !ok || user == nil {
		return fc.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadAttribute)).
			JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(fc, responseErrors.ErrBadAttribute)))
	}

	customerIdStr := fc.Query("id")
	if customerIdStr != "" {
		id, err := strconv.ParseUint(customerIdStr, 10, 64)
		if err != nil {
			return fiber.ErrBadRequest
		}

		if user.ID != uint(id) && !user.HasPermission(perms.UserReadAny) {
			return fc.Status(fiber.StatusForbidden).
				JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(fc, responseErrors.ErrForbidden)))
		}

		customerId = uint(id)
	} else {
		customerId = user.ID
	}

	customer, err := h.service.GetById(customerId)
	if err != nil {
		return fc.Status(responseErrors.GetErrorStatus(err)).
			JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(fc, err)))
	}

	return fc.JSON(response.Make(&customer, 0, i18n.T_(fc, response.Message_OK)))
}

func (h *customerHandler) listCustomers(fc fiber.Ctx) error {
	user, ok := localeExtractor.GetCustomer(fc)
	if !ok || user == nil {
		return fc.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadAttribute)).
			JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(fc, responseErrors.ErrBadAttribute)))
	}
	if !user.HasPermission(perms.UserReadAny) {
		return fc.Status(fiber.StatusForbidden).
			JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(fc, responseErrors.ErrForbidden)))
	}

	p, filt, err := query_params.ParseFilters[model.Customer](fc, columnMappingListUsers)
	if err != nil {
		return fc.Status(responseErrors.GetErrorStatus(err)).
			JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(fc, err)))
	}

	search := fc.Query("search")
	if search != "" {
		if !user.HasPermission(perms.UserReadAny) {
			return fc.Status(fiber.StatusForbidden).
				JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(fc, responseErrors.ErrForbidden)))
		}
	}

	customer, err := h.service.Find(user.LangID, p, filt, search)
	if err != nil {
		return fc.Status(responseErrors.GetErrorStatus(err)).
			JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(fc, err)))
	}

	return fc.JSON(response.Make(&customer, 0, i18n.T_(fc, response.Message_OK)))
}

var columnMappingListUsers map[string]string = map[string]string{
	"user_id":    "users.id",
	"email":      "users.email",
	"first_name": "users.first_name",
	"last_name":  "users.last_name",
}
