//
//  FGIAPManager.m
//  MaltBaby
//
//  Created by FoneG on 2020/5/7.
//

#import "FGIAPService.h"
#import "FGIAPServiceUtility.h"
#import "NSObject+FGIsNullOrEmpty.h"

static NSMutableDictionary *FGIAPServiceErrorMapsFromTransaction (SKPaymentTransaction *transaction) {
    NSMutableDictionary *errorMaps = [NSMutableDictionary dictionary];
    [errorMaps setValue:transaction.transactionIdentifier?:@"" forKey:@"transactionIdentifier"];
    [errorMaps setValue:transaction.originalTransaction.transactionIdentifier?:@"" forKey:@"originalTransaction.transactionIdentifier"];
    [errorMaps setValue:transaction.payment.applicationUsername?:@"" forKey:@"applicationUsername"];
    [errorMaps setValue:transaction.payment.productIdentifier?:@"" forKey:@"productIdentifier"];
    return errorMaps;
}

@interface FGIAPService () <SKPaymentTransactionObserver, SKRequestDelegate>
@property (nonatomic, strong) id<FGIAPVerifyTransaction> verifyTransaction;
@property (nonatomic, copy) FGIAPManagerBuyBlock buyProductCompleteBlock;
@property (nonatomic, strong) NSString *productIdentifier;
@property (nonatomic, strong)  SKPayment *APPStorePayment;
@end

@implementation FGIAPService

- (instancetype)initWithTransaction:(id<FGIAPVerifyTransaction>)verifyTransaction{
    if (self = [super init]) {
        
        _verifyTransaction = verifyTransaction;
                
        if ([SKPaymentQueue defaultQueue]) {
            [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
        }
    }
    return self;
}


- (void)buyProduct:(SKProduct *)product onCompletion:(nonnull FGIAPManagerBuyBlock)completion{

    if (![SKPaymentQueue canMakePayments]) {
        completion(@"Failed to obtain the internal purchase permission", FGIAPManagerPurchaseRusultFail);
        return;
    }
    if ([product.productIdentifier isNSStringAndNotEmpty]) {
        _productIdentifier = product.productIdentifier;
        _buyProductCompleteBlock = completion;
        SKMutablePayment *payment = [SKMutablePayment paymentWithProduct:product];
        if ([SKPaymentQueue defaultQueue]) {
            [[SKPaymentQueue defaultQueue] addPayment:payment];
        }
    }else{
        completion(@"The selected payment does not exist", FGIAPManagerPurchaseRusultFail);
    }
}

- (void)tryShouldAddStorePayments{
    if (_APPStorePayment && [SKPaymentQueue defaultQueue]) {
        [[SKPaymentQueue defaultQueue] addPayment:self.APPStorePayment];
    }
}

#pragma mark - SKPaymentTransactionObserver

- (void)paymentQueue:(SKPaymentQueue *)queue removedTransactions:(NSArray<SKPaymentTransaction *> *)transactions{
    FGLog(@"%s %ld", __func__, [SKPaymentQueue defaultQueue].transactions.count);
    if (![[SKPaymentQueue defaultQueue].transactions isNSArrayAndNotEmpty]) {
        /// all transactions finished
    }
}

- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
    for (SKPaymentTransaction *transaction in transactions)
    {
        switch (transaction.transactionState)
        {
            case SKPaymentTransactionStatePurchasing:
                FGLog(@"Add an payment to the list");
                break;
            case SKPaymentTransactionStatePurchased:
                FGLog(@"Customer paid successfully");
                [self completeTransaction:transaction retryWhenreceiptURLisEmpty:YES];
                break;
            case SKPaymentTransactionStateRestored:
                FGLog(@"The transaction has been recovered from the user's purchase history");
                [self completeTransaction:transaction retryWhenreceiptURLisEmpty:YES];
                break;
            case SKPaymentTransactionStateFailed:
                FGLog(@"Failure of commodity transaction");
                [self failedTransaction:transaction withError:FGIAPServiceErrorTypeNone];
                break;
            case SKPaymentTransactionStateDeferred:
                FGLog(@"Merchandise is suspended");
                break;
            default:
                ///
                break;
        }
    }
}

- (BOOL)paymentQueue:(SKPaymentQueue *)queue shouldAddStorePayment:(SKPayment *)payment forProduct:(SKProduct *)product API_AVAILABLE(ios(11.0)){
    BOOL shouldAddStorePayment = NO;
    if (_verifyTransaction && [_verifyTransaction respondsToSelector:@selector(paymentQueue:shouldAddStorePayment:forProduct:)]) {
        shouldAddStorePayment = [_verifyTransaction paymentQueue:queue shouldAddStorePayment:payment forProduct:product];
    }
    if (shouldAddStorePayment == NO) {
        _APPStorePayment = payment;
    }
    return shouldAddStorePayment;
}


#pragma mark - SKRequestDelegate

- (void)requestDidFinish:(SKRequest *)request{
    if ([request isKindOfClass:[SKReceiptRefreshRequest class]]) {
        SKReceiptRefreshRequest *RefreshRequest = (SKReceiptRefreshRequest *)request;
        SKPaymentTransaction *transaction = [RefreshRequest.receiptProperties valueForKey:@"transaction"];
        if (transaction) {
            [self completeTransaction:transaction retryWhenreceiptURLisEmpty:NO];
        }else{
            [self failedTransaction:transaction withError:FGIAPServiceErrorTypeReceiptNotExist];
        }
    }
}

- (void)request:(SKRequest *)request didFailWithError:(nonnull NSError *)error{
    if ([request isKindOfClass:[SKReceiptRefreshRequest class]]) {
        SKReceiptRefreshRequest *RefreshRequest = (SKReceiptRefreshRequest *)request;
        SKPaymentTransaction *transaction = [RefreshRequest.receiptProperties valueForKey:@"transaction"];
        [self failedTransaction:transaction withError:FGIAPServiceErrorTypeReceiptNotExist];
    }
}


#pragma mark - private method

- (void)completeTransaction:(SKPaymentTransaction *)transaction retryWhenreceiptURLisEmpty:(BOOL)retry{
    FGLog(@"%s %@ %@", __func__, transaction.transactionIdentifier, transaction.originalTransaction.transactionIdentifier);
            
    if (![transaction.transactionIdentifier isNSStringAndNotEmpty]) {
        [self failedTransaction:transaction withError:FGIAPServiceErrorTypeTransactionIdentifierNotExist];
        return;
    }
    
    NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
    if ([[NSFileManager defaultManager] fileExistsAtPath:receiptURL.path]) {
        
        NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];
        NSString *receiptDataText = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
        [self checkReceipt:receiptDataText withTransaction:transaction handler:nil];
        
    }else if (retry){
        
        SKReceiptRefreshRequest *receiptRefreshRequest = [[SKReceiptRefreshRequest alloc] initWithReceiptProperties:@{@"transaction":transaction}];
        receiptRefreshRequest.delegate = self;
        [receiptRefreshRequest start];
        
    }else{
        [self failedTransaction:transaction withError:FGIAPServiceErrorTypeReceiptNotExist];
    }
}


- (void)failedTransaction:(SKPaymentTransaction *)transaction withError:(FGIAPServiceErrorType)error{
    FGLog(@"%s Transaction error:%@ code:%ld", __func__, transaction.error.localizedDescription, transaction.error.code);
    
    BOOL finish = error == FGIAPServiceErrorTypeNone;
    
    if (finish && [SKPaymentQueue defaultQueue]) {
        [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
    }
    
    NSMutableDictionary *logStatistics = [NSMutableDictionary dictionaryWithDictionary:FGIAPServiceErrorMapsFromTransaction(transaction)];
    if (self.verifyTransaction && [self.verifyTransaction respondsToSelector:@selector(pushServiceErrorLogStatistics:error:)]) {
        [logStatistics setValue:@(error) forKey:@"error"];
        [self.verifyTransaction pushServiceErrorLogStatistics:logStatistics error:error];
    }
    
    if (_buyProductCompleteBlock) {
        FGIAPManagerPurchaseRusult result = FGIAPManagerPurchaseRusultHalfSuccess;
        if (error == FGIAPServiceErrorTypeNone) {
            result = transaction.error.code == SKErrorPaymentCancelled ? FGIAPManagerPurchaseRusultCancel : FGIAPManagerPurchaseRusultFail;
        }
        _buyProductCompleteBlock(transaction.error.localizedDescription, result);
    }
}



- (void)checkReceipt:(NSString *)receipt withTransaction:(SKPaymentTransaction *)transaction handler:(FGIAPVerifyTransactionBlock)handler{
    
    WS(wSelf);
    if (_verifyTransaction && [_verifyTransaction respondsToSelector:@selector(pushSuccessTradeReultToServer:transaction:complete:)]) {
        [_verifyTransaction pushSuccessTradeReultToServer:receipt transaction:transaction complete:^(NSString * _Nonnull message, NSError * _Nullable requestErr) {

            //polling verify transaction
            if (requestErr && requestErr.code != FGIAPServerOverdueErrorCode) {
                dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                    [wSelf checkReceipt:receipt withTransaction:transaction handler:handler];
                });
                return;
            }
            
            [wSelf finishTransaction:transaction result: FGIAPManagerPurchaseRusultSuccess message:message];
        }];
    }else{
        NSAssert(NO, @"You must configure the method: - pushSuccessTradeReultToServer:transaction:complete:");
    }
}


- (void)finishTransaction:(SKPaymentTransaction *)transaction result:(FGIAPManagerPurchaseRusult)result message:(NSString *)msg{
    
    FGLog(@"%s finishTransaction:%@", __func__, transaction.transactionIdentifier);
    
    if ([SKPaymentQueue defaultQueue]) {
        [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
    }
    
    if ([transaction.payment.productIdentifier isEqualToString:self.productIdentifier]) {
        self.productIdentifier = nil;
        if (_buyProductCompleteBlock) {
            _buyProductCompleteBlock(msg, result);
        }
    }
}

@end
