package handler

import (
	"apskel-pos-be/internal/appcontext"
	"apskel-pos-be/internal/constants"
	"apskel-pos-be/internal/contract"
	"apskel-pos-be/internal/logger"
	"apskel-pos-be/internal/service"
	"apskel-pos-be/internal/util"
	"apskel-pos-be/internal/validator"
	"strconv"

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

type IngredientUnitConverterHandler struct {
	converterService   service.IngredientUnitConverterService
	converterValidator validator.IngredientUnitConverterValidator
}

func NewIngredientUnitConverterHandler(
	converterService service.IngredientUnitConverterService,
	converterValidator validator.IngredientUnitConverterValidator,
) *IngredientUnitConverterHandler {
	return &IngredientUnitConverterHandler{
		converterService:   converterService,
		converterValidator: converterValidator,
	}
}

func (h *IngredientUnitConverterHandler) CreateIngredientUnitConverter(c *gin.Context) {
	ctx := c.Request.Context()
	contextInfo := appcontext.FromGinContext(ctx)

	var req contract.CreateIngredientUnitConverterRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		logger.FromContext(c.Request.Context()).WithError(err).Error("IngredientUnitConverterHandler::CreateIngredientUnitConverter -> request binding failed")
		validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
		util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "IngredientUnitConverterHandler::CreateIngredientUnitConverter")
		return
	}

	validationError, validationErrorCode := h.converterValidator.ValidateCreateIngredientUnitConverterRequest(&req)
	if validationError != nil {
		validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
		util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "IngredientUnitConverterHandler::CreateIngredientUnitConverter")
		return
	}

	converterResponse := h.converterService.CreateIngredientUnitConverter(ctx, contextInfo, &req)
	if converterResponse.HasErrors() {
		errorResp := converterResponse.GetErrors()[0]
		logger.FromContext(ctx).WithError(errorResp).Error("IngredientUnitConverterHandler::CreateIngredientUnitConverter -> Failed to create ingredient unit converter from service")
	}

	util.HandleResponse(c.Writer, c.Request, converterResponse, "IngredientUnitConverterHandler::CreateIngredientUnitConverter")
}

func (h *IngredientUnitConverterHandler) UpdateIngredientUnitConverter(c *gin.Context) {
	ctx := c.Request.Context()
	contextInfo := appcontext.FromGinContext(ctx)

	converterIDStr := c.Param("id")
	converterID, err := uuid.Parse(converterIDStr)
	if err != nil {
		logger.FromContext(ctx).WithError(err).Error("IngredientUnitConverterHandler::UpdateIngredientUnitConverter -> Invalid converter ID")
		validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid converter ID")
		util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "IngredientUnitConverterHandler::UpdateIngredientUnitConverter")
		return
	}

	var req contract.UpdateIngredientUnitConverterRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		logger.FromContext(ctx).WithError(err).Error("IngredientUnitConverterHandler::UpdateIngredientUnitConverter -> request binding failed")
		validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, "Invalid request body")
		util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "IngredientUnitConverterHandler::UpdateIngredientUnitConverter")
		return
	}

	validationError, validationErrorCode := h.converterValidator.ValidateUpdateIngredientUnitConverterRequest(&req)
	if validationError != nil {
		validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
		util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "IngredientUnitConverterHandler::UpdateIngredientUnitConverter")
		return
	}

	converterResponse := h.converterService.UpdateIngredientUnitConverter(ctx, contextInfo, converterID, &req)
	if converterResponse.HasErrors() {
		errorResp := converterResponse.GetErrors()[0]
		logger.FromContext(ctx).WithError(errorResp).Error("IngredientUnitConverterHandler::UpdateIngredientUnitConverter -> Failed to update ingredient unit converter from service")
	}

	util.HandleResponse(c.Writer, c.Request, converterResponse, "IngredientUnitConverterHandler::UpdateIngredientUnitConverter")
}

func (h *IngredientUnitConverterHandler) DeleteIngredientUnitConverter(c *gin.Context) {
	ctx := c.Request.Context()
	contextInfo := appcontext.FromGinContext(ctx)

	converterIDStr := c.Param("id")
	converterID, err := uuid.Parse(converterIDStr)
	if err != nil {
		logger.FromContext(ctx).WithError(err).Error("IngredientUnitConverterHandler::DeleteIngredientUnitConverter -> Invalid converter ID")
		validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid converter ID")
		util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "IngredientUnitConverterHandler::DeleteIngredientUnitConverter")
		return
	}

	converterResponse := h.converterService.DeleteIngredientUnitConverter(ctx, contextInfo, converterID)
	if converterResponse.HasErrors() {
		errorResp := converterResponse.GetErrors()[0]
		logger.FromContext(ctx).WithError(errorResp).Error("IngredientUnitConverterHandler::DeleteIngredientUnitConverter -> Failed to delete ingredient unit converter from service")
	}

	util.HandleResponse(c.Writer, c.Request, converterResponse, "IngredientUnitConverterHandler::DeleteIngredientUnitConverter")
}

func (h *IngredientUnitConverterHandler) GetIngredientUnitConverter(c *gin.Context) {
	ctx := c.Request.Context()
	contextInfo := appcontext.FromGinContext(ctx)

	converterIDStr := c.Param("id")
	converterID, err := uuid.Parse(converterIDStr)
	if err != nil {
		logger.FromContext(ctx).WithError(err).Error("IngredientUnitConverterHandler::GetIngredientUnitConverter -> Invalid converter ID")
		validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid converter ID")
		util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "IngredientUnitConverterHandler::GetIngredientUnitConverter")
		return
	}

	converterResponse := h.converterService.GetIngredientUnitConverter(ctx, contextInfo, converterID)
	if converterResponse.HasErrors() {
		errorResp := converterResponse.GetErrors()[0]
		logger.FromContext(ctx).WithError(errorResp).Error("IngredientUnitConverterHandler::GetIngredientUnitConverter -> Failed to get ingredient unit converter from service")
	}

	util.HandleResponse(c.Writer, c.Request, converterResponse, "IngredientUnitConverterHandler::GetIngredientUnitConverter")
}

func (h *IngredientUnitConverterHandler) ListIngredientUnitConverters(c *gin.Context) {
	ctx := c.Request.Context()
	contextInfo := appcontext.FromGinContext(ctx)

	req := &contract.ListIngredientUnitConvertersRequest{
		Page:  1,
		Limit: 10,
	}

	// Parse query parameters
	if pageStr := c.Query("page"); pageStr != "" {
		if page, err := strconv.Atoi(pageStr); err == nil {
			req.Page = page
		}
	}

	if limitStr := c.Query("limit"); limitStr != "" {
		if limit, err := strconv.Atoi(limitStr); err == nil {
			req.Limit = limit
		}
	}

	if search := c.Query("search"); search != "" {
		req.Search = search
	}

	if ingredientIDStr := c.Query("ingredient_id"); ingredientIDStr != "" {
		if ingredientID, err := uuid.Parse(ingredientIDStr); err == nil {
			req.IngredientID = &ingredientID
		}
	}

	if fromUnitIDStr := c.Query("from_unit_id"); fromUnitIDStr != "" {
		if fromUnitID, err := uuid.Parse(fromUnitIDStr); err == nil {
			req.FromUnitID = &fromUnitID
		}
	}

	if toUnitIDStr := c.Query("to_unit_id"); toUnitIDStr != "" {
		if toUnitID, err := uuid.Parse(toUnitIDStr); err == nil {
			req.ToUnitID = &toUnitID
		}
	}

	if isActiveStr := c.Query("is_active"); isActiveStr != "" {
		if isActive, err := strconv.ParseBool(isActiveStr); err == nil {
			req.IsActive = &isActive
		}
	}

	validationError, validationErrorCode := h.converterValidator.ValidateListIngredientUnitConvertersRequest(req)
	if validationError != nil {
		validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
		util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "IngredientUnitConverterHandler::ListIngredientUnitConverters")
		return
	}

	converterResponse := h.converterService.ListIngredientUnitConverters(ctx, contextInfo, req)
	if converterResponse.HasErrors() {
		errorResp := converterResponse.GetErrors()[0]
		logger.FromContext(ctx).WithError(errorResp).Error("IngredientUnitConverterHandler::ListIngredientUnitConverters -> Failed to list ingredient unit converters from service")
	}

	util.HandleResponse(c.Writer, c.Request, converterResponse, "IngredientUnitConverterHandler::ListIngredientUnitConverters")
}

func (h *IngredientUnitConverterHandler) GetConvertersForIngredient(c *gin.Context) {
	ctx := c.Request.Context()
	contextInfo := appcontext.FromGinContext(ctx)

	ingredientIDStr := c.Param("ingredient_id")
	ingredientID, err := uuid.Parse(ingredientIDStr)
	if err != nil {
		logger.FromContext(ctx).WithError(err).Error("IngredientUnitConverterHandler::GetConvertersForIngredient -> Invalid ingredient ID")
		validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid ingredient ID")
		util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "IngredientUnitConverterHandler::GetConvertersForIngredient")
		return
	}

	converterResponse := h.converterService.GetConvertersForIngredient(ctx, contextInfo, ingredientID)
	if converterResponse.HasErrors() {
		errorResp := converterResponse.GetErrors()[0]
		logger.FromContext(ctx).WithError(errorResp).Error("IngredientUnitConverterHandler::GetConvertersForIngredient -> Failed to get converters for ingredient from service")
	}

	util.HandleResponse(c.Writer, c.Request, converterResponse, "IngredientUnitConverterHandler::GetConvertersForIngredient")
}

func (h *IngredientUnitConverterHandler) ConvertUnit(c *gin.Context) {
	ctx := c.Request.Context()
	contextInfo := appcontext.FromGinContext(ctx)

	var req contract.ConvertUnitRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		logger.FromContext(c.Request.Context()).WithError(err).Error("IngredientUnitConverterHandler::ConvertUnit -> request binding failed")
		validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
		util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "IngredientUnitConverterHandler::ConvertUnit")
		return
	}

	validationError, validationErrorCode := h.converterValidator.ValidateConvertUnitRequest(&req)
	if validationError != nil {
		validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
		util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "IngredientUnitConverterHandler::ConvertUnit")
		return
	}

	converterResponse := h.converterService.ConvertUnit(ctx, contextInfo, &req)
	if converterResponse.HasErrors() {
		errorResp := converterResponse.GetErrors()[0]
		logger.FromContext(ctx).WithError(errorResp).Error("IngredientUnitConverterHandler::ConvertUnit -> Failed to convert unit from service")
	}

	util.HandleResponse(c.Writer, c.Request, converterResponse, "IngredientUnitConverterHandler::ConvertUnit")
}

