package callback

import (
	"context"
	"fmt"
	"log"

	"go.uber.org/zap"
	"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/errors"
	"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models"
)

type accountRepository interface {
	FindByUserID(context.Context, string) (*models.Account, errors.Error)
}

type historyService interface {
	CreateHistory(ctx context.Context, history *models.History) (*models.History, errors.Error)
}

type walletService interface {
	ReplenishAccountWallet(context.Context, *models.ReplenishAccountWallet) (*models.Account, errors.Error)
}

type PaymentCallbackServiceDeps struct {
	Logger            *zap.Logger
	AccountRepository accountRepository
	WalletService     walletService
	HistoryService    historyService
}

type PaymentCallbackService struct {
	logger            *zap.Logger
	accountRepository accountRepository
	walletService     walletService
	historyService    historyService
}

func NewPaymentCallbackService(deps PaymentCallbackServiceDeps) *PaymentCallbackService {
	if deps.Logger == nil {
		log.Panicln("logger is nil on <New (payment callback service)>")
	}

	if deps.AccountRepository == nil {
		log.Panicln("AccountRepository is nil on <New (payment callback service)>")
	}

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

	if deps.HistoryService == nil {
		log.Panicln("HistoryService is nil on <New (payment callback service)>")
	}

	return &PaymentCallbackService{
		logger:            deps.Logger,
		accountRepository: deps.AccountRepository,
		walletService:     deps.WalletService,
		historyService:    deps.HistoryService,
	}
}

func (receiver *PaymentCallbackService) SuccessEvent(ctx context.Context, event *models.PaymentEvent) errors.Error {
	account, err := receiver.accountRepository.FindByUserID(ctx, event.UserID)
	if err != nil {
		receiver.logger.Error("failed to get account on <SuccessEvent> of <PaymentCallbackService>", zap.Error(err))
		return err
	}

	if account.Wallet.LastPaymentID == event.PaymentID {
		receiver.logger.Info("payment already was executed on <SuccessEvent> of <PaymentCallbackService>", zap.String("paymentID", event.PaymentID))
		return nil
	}

	if _, err := receiver.walletService.ReplenishAccountWallet(ctx, &models.ReplenishAccountWallet{
		Cash:      event.Amount,
		Currency:  event.Currency,
		PaymentID: event.PaymentID,
		Account:   account,
	}); err != nil {
		receiver.logger.Error("failed to replenish wallet on <SuccessEvent> of <PaymentCallbackService>", zap.Error(err))
		return err
	}

	go func() {
		if _, err := receiver.historyService.CreateHistory(ctx, &models.History{
			UserID:     account.UserID,
			Comment:    event.Message,
			Key:        event.Key,
			RawDetails: fmt.Sprintf("%d%s", event.Amount, event.Currency),
		}); err != nil {
			receiver.logger.Error("failed to create history on <SuccessEvent> of <PaymentCallbackService>", zap.Error(err))
		}
	}()

	return nil
}

func (receiver *PaymentCallbackService) FailureEvent(ctx context.Context, event *models.PaymentEvent) errors.Error {
	if _, err := receiver.historyService.CreateHistory(ctx, &models.History{
		UserID:     event.UserID,
		Comment:    event.Message,
		Key:        event.Key,
		RawDetails: fmt.Sprintf("%d%s", event.Amount, event.Currency),
	}); err != nil {
		receiver.logger.Error("failed to create history on <FailureEvent> of <PaymentCallbackService>", zap.Error(err))
		return err
	}

	return nil
}
