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 OutletHandler struct {
	outletService   service.OutletService
	outletValidator validator.OutletValidator
}

func NewOutletHandler(outletService service.OutletService, outletValidator validator.OutletValidator) *OutletHandler {
	return &OutletHandler{
		outletService:   outletService,
		outletValidator: outletValidator,
	}
}

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

	req := &contract.ListOutletsRequest{
		Page:           1,
		Limit:          10,
		OrganizationID: contextInfo.OrganizationID,
	}

	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 businessType := c.Query("business_type"); businessType != "" {
		req.BusinessType = &businessType
	}

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

	validationError, validationErrorCode := h.outletValidator.ValidateListOutletsRequest(req)
	if validationError != nil {
		logger.FromContext(ctx).WithError(validationError).Error("OutletHandler::ListOutlets -> request validation failed")
		validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
		util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "OutletHandler::ListOutlets")
		return
	}

	outletsResponse := h.outletService.ListOutlets(ctx, req)
	if outletsResponse.HasErrors() {
		errorResp := outletsResponse.GetErrors()[0]
		logger.FromContext(ctx).WithError(errorResp).Error("OutletHandler::ListOutlets -> Failed to list outlets from service")
	}

	util.HandleResponse(c.Writer, c.Request, outletsResponse, "OutletHandler::ListOutlets")
}

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

	outletIDStr := c.Param("id")
	outletID, err := uuid.Parse(outletIDStr)

	if err != nil {
		logger.FromContext(ctx).WithError(err).Error("OutletHandler::GetOutlet -> Invalid outlet ID")
		validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid outlet ID")
		util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "OutletHandler::GetOutlet")
		return
	}

	outletResponse := h.outletService.GetOutletByID(ctx, contextInfo.OrganizationID, outletID)
	if outletResponse.HasErrors() {
		errorResp := outletResponse.GetErrors()[0]
		logger.FromContext(ctx).WithError(errorResp).Error("OutletHandler::GetOutlet -> Failed to get outlet from service")
	}

	util.HandleResponse(c.Writer, c.Request, outletResponse, "OutletHandler::GetOutlet")
}

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

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

	var req contract.UpdateOutletRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		logger.FromContext(ctx).WithError(err).Error("OutletHandler::UpdateOutlet -> Failed to bind JSON")
		validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid request body")
		util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "OutletHandler::UpdateOutlet")
		return
	}

	req.OrganizationID = contextInfo.OrganizationID

	validationError, validationErrorCode := h.outletValidator.ValidateUpdateOutletRequest(&req)
	if validationError != nil {
		logger.FromContext(ctx).WithError(validationError).Error("OutletHandler::UpdateOutlet -> request validation failed")
		validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
		util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "OutletHandler::UpdateOutlet")
		return
	}

	outletResponse := h.outletService.UpdateOutlet(ctx, outletID, &req)
	if outletResponse.HasErrors() {
		errorResp := outletResponse.GetErrors()[0]
		logger.FromContext(ctx).WithError(errorResp).Error("OutletHandler::UpdateOutlet -> Failed to update outlet from service")
	}

	util.HandleResponse(c.Writer, c.Request, outletResponse, "OutletHandler::UpdateOutlet")
}
