package wallet

import (
	"context"
	"go.uber.org/zap"
	"log"
	"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/errors"
	"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/client"
	"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models"
	"penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/validate"
)

type accountRepository interface {
	ChangeWallet(ctx context.Context, userID string, wallet *models.Wallet) (*models.Account, errors.Error)
	FindByUserID(ctx context.Context, id string) (*models.Account, errors.Error)
}

type currencyClient interface {
	Translate(context.Context, *models.TranslateCurrency) (int64, errors.Error)
}

type verificationClient interface {
	GetVerification(ctx context.Context, token, userID string) (*models.Verification, errors.Error)
}

type authClient interface {
	GetUser(ctx context.Context, userID string) (*models.User, errors.Error)
}

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

type Deps struct {
	Logger             *zap.Logger
	Repository         accountRepository
	CurrencyClient     currencyClient
	HistoryService     historyService
	VerificationClient verificationClient
	AuthClient         authClient
	MailClient         *client.MailClient
}

type Service struct {
	logger             *zap.Logger
	repository         accountRepository
	currencyClient     currencyClient
	historyService     historyService
	verificationClient verificationClient
	authClient         authClient
	mailClient         *client.MailClient
}

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

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

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

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

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

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

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

	return &Service{
		logger:             deps.Logger,
		repository:         deps.Repository,
		currencyClient:     deps.CurrencyClient,
		verificationClient: deps.VerificationClient,
		authClient:         deps.AuthClient,
		mailClient:         deps.MailClient,
		historyService:     deps.HistoryService,
	}
}

func (receiver *Service) ReplenishAccountWallet(ctx context.Context, request *models.ReplenishAccountWallet) (*models.Account, errors.Error) {
	if validate.IsStringEmpty(request.Account.Wallet.Currency) {
		request.Account.Wallet.Currency = models.InternalCurrencyKey
	}

	cash := request.Cash

	if request.Currency != request.Account.Wallet.Currency {
		translatedCash, translateErr := receiver.currencyClient.Translate(ctx, &models.TranslateCurrency{
			Money: request.Cash,
			From:  request.Currency,
			To:    request.Account.Wallet.Currency,
		})
		if translateErr != nil {
			receiver.logger.Error("failed to translate cash on <ReplenishAccountWallet> of <WalletService>", zap.Error(translateErr))
			return nil, translateErr
		}

		cash = translatedCash
	}

	if request.Currency == models.InternalCurrencyKey {
		updatedAccount, changeErr := receiver.repository.ChangeWallet(ctx, request.Account.UserID, &models.Wallet{
			Cash:            request.Account.Wallet.Cash + cash,
			Money:           request.Account.Wallet.Money + request.Cash,
			Spent:           request.Account.Wallet.Spent,
			PurchasesAmount: request.Account.Wallet.PurchasesAmount,
			Currency:        request.Account.Wallet.Currency,
			LastPaymentID:   request.PaymentID,
		})
		if changeErr != nil {
			receiver.logger.Error("failed to replenish wallet on <ReplenishAccountWallet> of <WalletService>",
				zap.Error(changeErr),
				zap.String("Currency", request.Account.Wallet.Currency),
				zap.Int64("Money", request.Account.Wallet.Money+request.Cash),
				zap.Int64("Cash", request.Account.Wallet.Cash+cash),
			)

			return nil, changeErr
		}

		// go func() {
		// 	if _, historyErr := receiver.historyService.CreateHistory(ctx, &models.History{
		// 		Key:     models.CustomerHistoryKeyReplenish,
		// 		UserID:  request.Account.UserID,
		// 		Comment: "Успешное пополнение средств (Без конвертации валюты)",
		// 		//		RawDetails: fmt.Sprintf("%d%s", cash, models.InternalCurrencyKey),
		// 	}); historyErr != nil {
		// 		receiver.logger.Error("failed to insert history on <ReplenishAccountWallet> of <WalletService>", zap.Error(historyErr))
		// 	}
		// }()
		//
		return updatedAccount, nil
	}

	money, err := receiver.currencyClient.Translate(ctx, &models.TranslateCurrency{
		Money: request.Cash,
		From:  request.Currency,
		To:    models.InternalCurrencyKey,
	})
	if err != nil {
		receiver.logger.Error("failed to translate money on <ReplenishAccountWallet> of <WalletService>", zap.Error(err))
		return nil, err
	}

	updatedAccount, err := receiver.repository.ChangeWallet(ctx, request.Account.UserID, &models.Wallet{
		Cash:            request.Account.Wallet.Cash + cash,
		Money:           request.Account.Wallet.Money + money,
		PurchasesAmount: request.Account.Wallet.PurchasesAmount + money,
		Spent:           request.Account.Wallet.Spent,
		Currency:        request.Account.Wallet.Currency,
		LastPaymentID:   request.PaymentID,
	})
	if err != nil {
		receiver.logger.Error("failed to replenish wallet on <ReplenishAccountWallet> of <WalletService>",
			zap.Error(err),
			zap.String("Currency", request.Account.Wallet.Currency),
			zap.Int64("Money", request.Account.Wallet.Money+money),
			zap.Int64("Cash", request.Account.Wallet.Cash+cash),
			zap.Bool("Is currensy equal internal", request.Currency == models.InternalCurrencyKey),
		)

		return nil, err
	}

	// go func() {
	// 	if _, historyErr := receiver.historyService.CreateHistory(ctx, &models.History{
	// 		Key:     models.CustomerHistoryKeyReplenish,
	// 		UserID:  request.Account.UserID,
	// 		Comment: "Успешное пополнение средств (C конвертацией валюты)",
	// 		//RawDetails: fmt.Sprintf("%d%s", cash, request.Currency),
	// 	}); historyErr != nil {
	// 		receiver.logger.Error("failed to insert history on <ReplenishAccountWallet> of <WalletService>", zap.Error(historyErr))
	// 	}
	// }()

	return updatedAccount, nil
}
