package orchestrator

import (
	"context"
	"time"

	"github.com/tech/sendico/payments/orchestrator/storage"
	"github.com/tech/sendico/payments/orchestrator/storage/model"
	"github.com/tech/sendico/pkg/mlogger"
	orchestratorv1 "github.com/tech/sendico/pkg/proto/payments/orchestrator/v1"
)

type paymentEngine interface {
	EnsureRepository(ctx context.Context) error
	BuildPaymentQuote(ctx context.Context, orgRef string, req *orchestratorv1.QuotePaymentRequest) (*orchestratorv1.PaymentQuote, time.Time, error)
	ResolvePaymentQuote(ctx context.Context, in quoteResolutionInput) (*orchestratorv1.PaymentQuote, *orchestratorv1.PaymentIntent, error)
	ExecutePayment(ctx context.Context, store storage.PaymentsStore, payment *model.Payment, quote *orchestratorv1.PaymentQuote) error
	Repository() storage.Repository
}

type defaultPaymentEngine struct {
	svc *Service
}

func (e defaultPaymentEngine) EnsureRepository(ctx context.Context) error {
	return e.svc.ensureRepository(ctx)
}

func (e defaultPaymentEngine) BuildPaymentQuote(ctx context.Context, orgRef string, req *orchestratorv1.QuotePaymentRequest) (*orchestratorv1.PaymentQuote, time.Time, error) {
	return e.svc.buildPaymentQuote(ctx, orgRef, req)
}

func (e defaultPaymentEngine) ResolvePaymentQuote(ctx context.Context, in quoteResolutionInput) (*orchestratorv1.PaymentQuote, *orchestratorv1.PaymentIntent, error) {
	return e.svc.resolvePaymentQuote(ctx, in)
}

func (e defaultPaymentEngine) ExecutePayment(ctx context.Context, store storage.PaymentsStore, payment *model.Payment, quote *orchestratorv1.PaymentQuote) error {
	return e.svc.executePayment(ctx, store, payment, quote)
}

func (e defaultPaymentEngine) Repository() storage.Repository {
	return e.svc.storage
}

type paymentCommandFactory struct {
	engine paymentEngine
	logger mlogger.Logger
}

func newPaymentCommandFactory(engine paymentEngine, logger mlogger.Logger) *paymentCommandFactory {
	return &paymentCommandFactory{
		engine: engine,
		logger: logger.Named("commands"),
	}
}

func (f *paymentCommandFactory) QuotePayment() *quotePaymentCommand {
	return &quotePaymentCommand{
		engine: f.engine,
		logger: f.logger.Named("quote_payment"),
	}
}

func (f *paymentCommandFactory) QuotePayments() *quotePaymentsCommand {
	return &quotePaymentsCommand{
		engine: f.engine,
		logger: f.logger.Named("quote_payments"),
	}
}

func (f *paymentCommandFactory) InitiatePayment() *initiatePaymentCommand {
	return &initiatePaymentCommand{
		engine: f.engine,
		logger: f.logger.Named("initiate_payment"),
	}
}

func (f *paymentCommandFactory) InitiatePayments() *initiatePaymentsCommand {
	return &initiatePaymentsCommand{
		engine: f.engine,
		logger: f.logger.Named("initiate_payments"),
	}
}

func (f *paymentCommandFactory) CancelPayment() *cancelPaymentCommand {
	return &cancelPaymentCommand{
		engine: f.engine,
		logger: f.logger.Named("cancel_payment"),
	}
}

func (f *paymentCommandFactory) InitiateConversion() *initiateConversionCommand {
	return &initiateConversionCommand{
		engine: f.engine,
		logger: f.logger.Named("initiate_conversion"),
	}
}
