#import <Foundation/Foundation.h>
#import "BTAPIClient.h"
#import "BTPaymentMethodNonce.h"

NS_ASSUME_NONNULL_BEGIN

extern NSString * const BTTokenizationServiceErrorDomain;
extern NSString * const BTTokenizationServiceAppSwitchDelegateOption;
extern NSString * const BTTokenizationServiceViewPresentingDelegateOption;
extern NSString * const BTTokenizationServicePayPalScopesOption;

typedef NS_ENUM(NSInteger, BTTokenizationServiceError) {
    BTTokenizationServiceErrorUnknown = 0,
    BTTokenizationServiceErrorTypeNotRegistered,
};

/// A tokenization service that supports registration of tokenizers at runtime.
///
/// @note `BTTokenizationService` provides access to tokenization services from payment options
/// (e.g. `BTPayPalDriver`) without introducing compile-time dependencies on the frameworks.

@interface BTTokenizationService : NSObject

/// The singleton instance of the tokenization service
+ (instancetype)sharedService;

/// Registers a block to execute for a given type when `tokenizeType:withAPIClient:completion:` or
/// `tokenizeType:options:withAPIClient:completion:` are invoked.
///
/// @param type A type string to identify the tokenization block. Providing a type that has already
///        been registered will overwrite the previously registered tokenization block.
/// @param tokenizationBlock The tokenization block to register for a type.
- (void)registerType:(NSString *)type withTokenizationBlock:(void(^)(BTAPIClient *apiClient, NSDictionary * _Nullable options, void(^)(BTPaymentMethodNonce * _Nullable paymentMethodNonce, NSError * _Nullable error)))tokenizationBlock;

/// Indicates whether a type has been registered with a valid tokenization block.
- (BOOL)isTypeAvailable:(NSString *)type;

/// Perform tokenization for the given type. This will execute the tokenization block that has been
/// registered for the type.
///
/// @param type The tokenization type to perform
/// @param apiClient The API client to use when performing tokenization.
/// @param completion The completion block to invoke when tokenization has completed.
- (void)tokenizeType:(NSString *)type
       withAPIClient:(BTAPIClient *)apiClient
          completion:(void(^)(BTPaymentMethodNonce * _Nullable paymentMethodNonce, NSError * _Nullable error))completion;

/// Perform tokenization for the given type. This will execute the tokenization block that has been
/// registered for the type.
///
/// @param type The tokenization type to perform
/// @param options A dictionary of data to use when invoking the tokenization block. This can be
///        used to pass data into a tokenization client/driver, e.g. credit card raw details.
/// @param apiClient The API client to use when performing tokenization.
/// @param completion The completion block to invoke when tokenization has completed.
- (void)tokenizeType:(NSString *)type
             options:(nullable NSDictionary<NSString *, id> *)options
       withAPIClient:(BTAPIClient *)apiClient
          completion:(void(^)(BTPaymentMethodNonce * _Nullable paymentMethodNonce, NSError * _Nullable error))completion;

@property (nonatomic, readonly, strong) NSArray <NSString *> *allTypes;

@end

NS_ASSUME_NONNULL_END
