package wallet

import (
	"fmt"
	"log"
	"net/http"

	"github.com/labstack/echo/v4"
	"go.uber.org/zap"
	"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/errors"
	"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models"
	"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/service/payment"
	"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/service/wallet"
	"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/utils"
	"penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/echotools"
	"penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/validate"
)

type Deps struct {
	Logger         *zap.Logger
	WalletService  *wallet.Service
	PaymentService *payment.Service
}

type Controller struct {
	logger         *zap.Logger
	walletService  *wallet.Service
	paymentService *payment.Service
}

func New(deps Deps) *Controller {
	if deps.Logger == nil {
		log.Panicln("logger is nil on <New (wallet controller)>")
	}

	if deps.WalletService == nil {
		log.Panicln("wallet service is nil on <New (wallet controller)>")
	}

	if deps.PaymentService == nil {
		log.Panicln("payment service is nil on <New (wallet controller)>")
	}

	return &Controller{
		logger:         deps.Logger,
		walletService:  deps.WalletService,
		paymentService: deps.PaymentService,
	}
}

func (receiver *Controller) ChangeCurrency(ctx echo.Context) error {
	userID, ok := ctx.Get(models.AuthJWTDecodedUserIDKey).(string)
	if !ok {
		receiver.logger.Error("failed to convert jwt payload to string on <ChangeCurrency> of <WallerController>")

		return errors.HTTP(ctx, errors.New(
			fmt.Errorf("failed to convert jwt payload to string: %s", userID),
			errors.ErrInvalidArgs,
		))
	}

	request, bindErr := echotools.Bind[models.ChangeCurrency](ctx)
	if bindErr != nil {
		receiver.logger.Error("failed to bind body on <ChangeCurrency> of <WalletController>", zap.Error(bindErr))
		return errors.HTTP(ctx, errors.New(
			fmt.Errorf("failed to parse body on <ChangeCurrency> of <WalletController>: %w", bindErr),
			errors.ErrInvalidArgs,
		))
	}

	if validate.IsStringEmpty(request.Currency) {
		return errors.HTTP(ctx, errors.New(
			fmt.Errorf("empty currency key on <ChangeCurrency> of <WalletController>: %w", errors.ErrInvalidArgs),
			errors.ErrInvalidArgs,
		))
	}

	account, err := receiver.walletService.ChangeCurrency(ctx.Request().Context(), userID, request.Currency)
	if err != nil {
		receiver.logger.Error("failed to put money on <ChangeCurrency> of <WalletController>", zap.Error(err))
		return errors.HTTP(ctx, err)
	}

	return ctx.JSON(http.StatusOK, account)
}

func (receiver *Controller) GetPaymentLink(ctx echo.Context) error {
	userID, ok := ctx.Get(models.AuthJWTDecodedUserIDKey).(string)
	if !ok {
		receiver.logger.Error("failed to convert jwt payload to string on <GetPaymentLink> of <WallerController>")

		return errors.HTTP(ctx, errors.New(
			fmt.Errorf("failed to convert jwt payload to string: %s", userID),
			errors.ErrInvalidArgs,
		))
	}

	request, bindErr := echotools.Bind[models.GetPaymentLinkBody](ctx)
	if bindErr != nil {
		receiver.logger.Error("failed to bind body on <GetPaymentLink> of <WalletController>", zap.Error(bindErr))
		return errors.HTTP(ctx, errors.New(
			fmt.Errorf("failed to parse body on <GetPaymentLink> of <WalletController>: %w", bindErr),
			errors.ErrInvalidArgs,
		))
	}

	if validateErr := utils.ValidateGetPaymentLinkBody(request); validateErr != nil {
		receiver.logger.Error("failed to validate body on <GetPaymentLink> of <WalletController>", zap.Error(validateErr))
		return errors.HTTP(ctx, validateErr)
	}

	link, err := receiver.paymentService.GetPaymentLink(ctx.Request().Context(), &models.GetPaymentLinkRequest{
		Body:     request,
		UserID:   userID,
		ClientIP: ctx.RealIP(),
	})
	if err != nil {
		receiver.logger.Error("failed to get payment link on <GetPaymentLink> of <WalletController>", zap.Error(err))
		return errors.HTTP(ctx, err)
	}

	return ctx.JSON(http.StatusOK, &models.GetPaymentLinkResponse{Link: link})
}
