package handler

import (
	"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"
)

type VoucherHandler struct {
	voucherService   service.VoucherService
	voucherValidator validator.VoucherValidator
}

func NewVoucherHandler(
	voucherService service.VoucherService,
	voucherValidator validator.VoucherValidator,
) *VoucherHandler {
	return &VoucherHandler{
		voucherService:   voucherService,
		voucherValidator: voucherValidator,
	}
}

func (h *VoucherHandler) GetRandomVouchersForSpin(c *gin.Context) {
	ctx := c.Request.Context()

	req := &contract.ListVouchersForSpinRequest{
		Limit: 10, // Default limit
	}

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

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

	vouchersResponse, err := h.voucherService.GetRandomVouchersForSpin(c.Request.Context(), req)
	if err != nil {
		logger.FromContext(ctx).WithError(err).Error("VoucherHandler::GetRandomVouchersForSpin -> Failed to get random vouchers from service")
		errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error())
		util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{errorResp}), "VoucherHandler::GetRandomVouchersForSpin")
		return
	}

	logger.FromContext(ctx).Infof("VoucherHandler::GetRandomVouchersForSpin -> Successfully retrieved %d vouchers for spin", vouchersResponse.Count)
	util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(vouchersResponse), "VoucherHandler::GetRandomVouchersForSpin")
}

func (h *VoucherHandler) GetRandomVouchersByRows(c *gin.Context) {
	ctx := c.Request.Context()

	req := &contract.ListVouchersByRowsRequest{
		Rows: 4, // Default 4 rows
	}

	// Parse query parameters
	if rowsStr := c.Query("rows"); rowsStr != "" {
		if rows, err := strconv.Atoi(rowsStr); err == nil {
			req.Rows = rows
		}
	}

	// Parse winner_number parameter (optional)
	if winnerNumberStr := c.Query("winner_number"); winnerNumberStr != "" {
		if wn, err := strconv.Atoi(winnerNumberStr); err == nil {
			req.WinnerNumber = &wn
		}
	}

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

	vouchersResponse, err := h.voucherService.GetRandomVouchersByRows(c.Request.Context(), req)
	if err != nil {
		logger.FromContext(ctx).WithError(err).Error("VoucherHandler::GetRandomVouchersByRows -> Failed to get random vouchers by rows from service")
		errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error())
		util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{errorResp}), "VoucherHandler::GetRandomVouchersByRows")
		return
	}

	logger.FromContext(ctx).Infof("VoucherHandler::GetRandomVouchersByRows -> Successfully retrieved %d rows with %d total vouchers", vouchersResponse.TotalRows, vouchersResponse.TotalVouchers)
	util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(vouchersResponse), "VoucherHandler::GetRandomVouchersByRows")
}

func (h *VoucherHandler) GetVoucherByID(c *gin.Context) {
	ctx := c.Request.Context()

	voucherID, err := strconv.ParseInt(c.Param("id"), 10, 64)
	if err != nil {
		logger.FromContext(ctx).WithError(err).Error("VoucherHandler::GetVoucherByID -> Invalid voucher ID")
		validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid voucher ID")
		util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "VoucherHandler::GetVoucherByID")
		return
	}

	voucherResponse, err := h.voucherService.GetVoucherByID(c.Request.Context(), voucherID)
	if err != nil {
		logger.FromContext(ctx).WithError(err).Error("VoucherHandler::GetVoucherByID -> Failed to get voucher from service")
		errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error())
		util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{errorResp}), "VoucherHandler::GetVoucherByID")
		return
	}

	util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(voucherResponse), "VoucherHandler::GetVoucherByID")
}

func (h *VoucherHandler) GetVoucherByCode(c *gin.Context) {
	ctx := c.Request.Context()

	voucherCode := c.Param("code")
	if voucherCode == "" {
		logger.FromContext(ctx).Error("VoucherHandler::GetVoucherByCode -> Missing voucher code")
		validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, "Voucher code is required")
		util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "VoucherHandler::GetVoucherByCode")
		return
	}

	voucherResponse, err := h.voucherService.GetVoucherByCode(c.Request.Context(), voucherCode)
	if err != nil {
		logger.FromContext(ctx).WithError(err).Error("VoucherHandler::GetVoucherByCode -> Failed to get voucher from service")
		errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error())
		util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{errorResp}), "VoucherHandler::GetVoucherByCode")
		return
	}

	util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(voucherResponse), "VoucherHandler::GetVoucherByCode")
}

func (h *VoucherHandler) ListVouchers(c *gin.Context) {
	ctx := c.Request.Context()

	page := 1
	limit := 10

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

	if limitStr := c.Query("limit"); limitStr != "" {
		if l, err := strconv.Atoi(limitStr); err == nil && l > 0 && l <= 100 {
			limit = l
		}
	}

	vouchersResponse, err := h.voucherService.ListVouchers(c.Request.Context(), page, limit)
	if err != nil {
		logger.FromContext(ctx).WithError(err).Error("VoucherHandler::ListVouchers -> Failed to list vouchers from service")
		errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error())
		util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{errorResp}), "VoucherHandler::ListVouchers")
		return
	}

	util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(vouchersResponse), "VoucherHandler::ListVouchers")
}
