package client

import (
	"context"

	"github.com/tech/sendico/pkg/payments/rail"
	moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1"
	connectorv1 "github.com/tech/sendico/pkg/proto/connector/v1"
	ledgerv1 "github.com/tech/sendico/pkg/proto/ledger/v1"
)

// Fake implements Client for tests.
type Fake struct {
	ReadBalanceFn                   func(ctx context.Context, accountID string) (*moneyv1.Money, error)
	CreateTransactionFn             func(ctx context.Context, tx rail.LedgerTx) (string, error)
	HoldBalanceFn                   func(ctx context.Context, accountID string, amount string) error
	CreateAccountFn                 func(ctx context.Context, req *ledgerv1.CreateAccountRequest) (*ledgerv1.CreateAccountResponse, error)
	ListAccountsFn                  func(ctx context.Context, req *ledgerv1.ListAccountsRequest) (*ledgerv1.ListAccountsResponse, error)
	ListConnectorAccountsFn         func(ctx context.Context, req *connectorv1.ListAccountsRequest) (*connectorv1.ListAccountsResponse, error)
	PostCreditWithChargesFn         func(ctx context.Context, req *ledgerv1.PostCreditRequest) (*ledgerv1.PostResponse, error)
	PostDebitWithChargesFn          func(ctx context.Context, req *ledgerv1.PostDebitRequest) (*ledgerv1.PostResponse, error)
	PostExternalCreditWithChargesFn func(ctx context.Context, req *ledgerv1.PostCreditRequest) (*ledgerv1.PostResponse, error)
	PostExternalDebitWithChargesFn  func(ctx context.Context, req *ledgerv1.PostDebitRequest) (*ledgerv1.PostResponse, error)
	TransferInternalFn              func(ctx context.Context, req *ledgerv1.TransferRequest) (*ledgerv1.PostResponse, error)
	ApplyFXWithChargesFn            func(ctx context.Context, req *ledgerv1.FXRequest) (*ledgerv1.PostResponse, error)
	BlockAccountFn                  func(ctx context.Context, req *ledgerv1.BlockAccountRequest) (*ledgerv1.BlockAccountResponse, error)
	UnblockAccountFn                func(ctx context.Context, req *ledgerv1.UnblockAccountRequest) (*ledgerv1.UnblockAccountResponse, error)
	GetBalanceFn                    func(ctx context.Context, req *ledgerv1.GetBalanceRequest) (*ledgerv1.BalanceResponse, error)
	GetJournalEntryFn               func(ctx context.Context, req *ledgerv1.GetEntryRequest) (*ledgerv1.JournalEntryResponse, error)
	GetStatementFn                  func(ctx context.Context, req *ledgerv1.GetStatementRequest) (*ledgerv1.StatementResponse, error)
	CloseFn                         func() error
}

func (f *Fake) ReadBalance(ctx context.Context, accountID string) (*moneyv1.Money, error) {
	if f.ReadBalanceFn != nil {
		return f.ReadBalanceFn(ctx, accountID)
	}
	return &moneyv1.Money{}, nil
}

func (f *Fake) CreateTransaction(ctx context.Context, tx rail.LedgerTx) (string, error) {
	if f.CreateTransactionFn != nil {
		return f.CreateTransactionFn(ctx, tx)
	}
	return "", nil
}

func (f *Fake) HoldBalance(ctx context.Context, accountID string, amount string) error {
	if f.HoldBalanceFn != nil {
		return f.HoldBalanceFn(ctx, accountID, amount)
	}
	return nil
}

func (f *Fake) CreateAccount(ctx context.Context, req *ledgerv1.CreateAccountRequest) (*ledgerv1.CreateAccountResponse, error) {
	if f.CreateAccountFn != nil {
		return f.CreateAccountFn(ctx, req)
	}
	return &ledgerv1.CreateAccountResponse{}, nil
}

func (f *Fake) ListAccounts(ctx context.Context, req *ledgerv1.ListAccountsRequest) (*ledgerv1.ListAccountsResponse, error) {
	if f.ListAccountsFn != nil {
		return f.ListAccountsFn(ctx, req)
	}
	return &ledgerv1.ListAccountsResponse{}, nil
}

func (f *Fake) ListConnectorAccounts(ctx context.Context, req *connectorv1.ListAccountsRequest) (*connectorv1.ListAccountsResponse, error) {
	if f.ListConnectorAccountsFn != nil {
		return f.ListConnectorAccountsFn(ctx, req)
	}
	return &connectorv1.ListAccountsResponse{}, nil
}

func (f *Fake) PostCreditWithCharges(ctx context.Context, req *ledgerv1.PostCreditRequest) (*ledgerv1.PostResponse, error) {
	if f.PostCreditWithChargesFn != nil {
		return f.PostCreditWithChargesFn(ctx, req)
	}
	return &ledgerv1.PostResponse{}, nil
}

func (f *Fake) PostDebitWithCharges(ctx context.Context, req *ledgerv1.PostDebitRequest) (*ledgerv1.PostResponse, error) {
	if f.PostDebitWithChargesFn != nil {
		return f.PostDebitWithChargesFn(ctx, req)
	}
	return &ledgerv1.PostResponse{}, nil
}

func (f *Fake) PostExternalCreditWithCharges(ctx context.Context, req *ledgerv1.PostCreditRequest) (*ledgerv1.PostResponse, error) {
	if f.PostExternalCreditWithChargesFn != nil {
		return f.PostExternalCreditWithChargesFn(ctx, req)
	}
	return &ledgerv1.PostResponse{}, nil
}

func (f *Fake) PostExternalDebitWithCharges(ctx context.Context, req *ledgerv1.PostDebitRequest) (*ledgerv1.PostResponse, error) {
	if f.PostExternalDebitWithChargesFn != nil {
		return f.PostExternalDebitWithChargesFn(ctx, req)
	}
	return &ledgerv1.PostResponse{}, nil
}

func (f *Fake) TransferInternal(ctx context.Context, req *ledgerv1.TransferRequest) (*ledgerv1.PostResponse, error) {
	if f.TransferInternalFn != nil {
		return f.TransferInternalFn(ctx, req)
	}
	return &ledgerv1.PostResponse{}, nil
}

func (f *Fake) ApplyFXWithCharges(ctx context.Context, req *ledgerv1.FXRequest) (*ledgerv1.PostResponse, error) {
	if f.ApplyFXWithChargesFn != nil {
		return f.ApplyFXWithChargesFn(ctx, req)
	}
	return &ledgerv1.PostResponse{}, nil
}

func (f *Fake) BlockAccount(ctx context.Context, req *ledgerv1.BlockAccountRequest) (*ledgerv1.BlockAccountResponse, error) {
	if f.BlockAccountFn != nil {
		return f.BlockAccountFn(ctx, req)
	}
	return &ledgerv1.BlockAccountResponse{}, nil
}

func (f *Fake) UnblockAccount(ctx context.Context, req *ledgerv1.UnblockAccountRequest) (*ledgerv1.UnblockAccountResponse, error) {
	if f.UnblockAccountFn != nil {
		return f.UnblockAccountFn(ctx, req)
	}
	return &ledgerv1.UnblockAccountResponse{}, nil
}

func (f *Fake) GetBalance(ctx context.Context, req *ledgerv1.GetBalanceRequest) (*ledgerv1.BalanceResponse, error) {
	if f.GetBalanceFn != nil {
		return f.GetBalanceFn(ctx, req)
	}
	return &ledgerv1.BalanceResponse{}, nil
}

func (f *Fake) GetJournalEntry(ctx context.Context, req *ledgerv1.GetEntryRequest) (*ledgerv1.JournalEntryResponse, error) {
	if f.GetJournalEntryFn != nil {
		return f.GetJournalEntryFn(ctx, req)
	}
	return &ledgerv1.JournalEntryResponse{}, nil
}

func (f *Fake) GetStatement(ctx context.Context, req *ledgerv1.GetStatementRequest) (*ledgerv1.StatementResponse, error) {
	if f.GetStatementFn != nil {
		return f.GetStatementFn(ctx, req)
	}
	return &ledgerv1.StatementResponse{}, nil
}

func (f *Fake) Close() error {
	if f.CloseFn != nil {
		return f.CloseFn()
	}
	return nil
}
