import 'dart:async';

import 'package:classify_photo/classify_photo.dart';
import 'package:clean/sdk/pay/assist/product_type.dart';
import 'package:flutter/cupertino.dart';
import 'package:in_app_purchase/in_app_purchase.dart';

import '../code/agile_pay_code.dart';
import 'agile_pay_state_info.dart';
import 'apple_or_google_pay_info.dart';

abstract class AppleOrGooglePay extends AgilePayStateInfo {
  final AppleOrGooglePayInfo? _payInfo;

  late final StreamSubscription<List<PurchaseDetails>>
  _purchaseUpdatedSubscription;
  late final InAppPurchase _iap;

  final Duration timeout = const Duration(seconds: 10);

  bool isCheck = false;

  bool isRestoring = false;

  AppleOrGooglePay([this._payInfo]) {
    _iap = InAppPurchase.instance;
    _purchaseUpdatedSubscription =
        _iap.purchaseStream.listen((purchaseDetailsList) {
          listenToPurchaseUpdated(purchaseDetailsList);
        }, onDone: () {
          dispose();
        }, onError: (error) {});
  }

  Future<void> check() async {
    isCheck = true;
  }

  Future<void> restore() async {
    sendPayBefore();
    ClassifyPhoto().finishTransaction();

    isRestoring = false;

    final bool isAe = await isAvailable();
    if (!isAe) {
      sendError(AgilePayCode.payCodeNotConnectStore,
          AgilePayCode.getMessageByCode(AgilePayCode.payCodeNotConnectStore));
      return;
    }

    await InAppPurchase.instance.restorePurchases();
  }

  void pay() async {
    sendPayBefore();
    ClassifyPhoto().finishTransaction();

    isCheck = false;

    try {
      final bool isAe = await isAvailable();
      if (!isAe) {
        sendError(AgilePayCode.payCodeNotConnectStore,
            AgilePayCode.getMessageByCode(AgilePayCode.payCodeNotConnectStore));
        return;
      }

      if (_payInfo == null) {
        sendError(AgilePayCode.payCodeOrderInfoError,
            AgilePayCode.getMessageByCode(AgilePayCode.payCodeOrderInfoError));
        return;
      }

      final ProductDetailsResponse response =
      await queryProductDetails({_payInfo.productId});
      if (response.notFoundIDs.isNotEmpty || response.productDetails.isEmpty) {
        sendError(
            AgilePayCode.payCodeProductNotFindStore,
            AgilePayCode.getMessageByCode(
                AgilePayCode.payCodeProductNotFindStore));
        return;
      }
      List<ProductDetails> products = response.productDetails;
      for (var element in products) {
        bool isSend;
        if (_payInfo.type == ProductType.consumable) {
          isSend = await buyConsumable(
              purchaseParam: PurchaseParam(
                  productDetails: element,
                  applicationUserName: _payInfo.accountToken));
        } else {
          isSend = await buyNonConsumable(
              purchaseParam: PurchaseParam(
                  productDetails: element,
                  applicationUserName: _payInfo.accountToken));
        }
        if (!isSend) {
          sendError(
              AgilePayCode.payCodeRequestSendError,
              AgilePayCode.getMessageByCode(
                  AgilePayCode.payCodeRequestSendError));
          return;
        }
        return;
      }
    } catch (e) {
      if (e is TimeoutException) {
        sendError(AgilePayCode.payCodeNotConnectStore,
            AgilePayCode.getMessageByCode(AgilePayCode.payCodeNotConnectStore));
        return;
      }
      sendError(AgilePayCode.payCodeOtherError,
          AgilePayCode.getMessageByCode(AgilePayCode.payCodeOtherError));
      return;
    }
  }

  Future<bool> isAvailable() {
    return _iap.isAvailable().timeout(timeout);
  }

  Future<ProductDetailsResponse> queryProductDetails(Set<String> identifiers) {
    return InAppPurchase.instance.queryProductDetails(identifiers);
  }

  Future<bool> buyConsumable({required PurchaseParam purchaseParam}) {
    return _iap.buyConsumable(purchaseParam: purchaseParam);
  }

  Future<bool> buyNonConsumable({required PurchaseParam purchaseParam}) {
    return _iap.buyNonConsumable(purchaseParam: purchaseParam);
  }

  void dispose() {
    _purchaseUpdatedSubscription.cancel();
  }

  void listenToPurchaseUpdated(
      List<PurchaseDetails> purchaseDetailsList) async {
    for (var purchaseDetails in purchaseDetailsList) {
      debugPrint(
          'agilePay-purchasePay--PurchaseUpdated-> ${purchaseDetails.toString()}');
      if (purchaseDetails.status == PurchaseStatus.pending) {
        verifyPendingPurchase(purchaseDetails);
      } else {
        if (purchaseDetails.status == PurchaseStatus.error) {
          verifyErrorPurchase(purchaseDetails);
        } else if (purchaseDetails.status == PurchaseStatus.purchased && !isCheck) {
          verifySuccessPurchase(purchaseDetails);
        } else if (purchaseDetails.status == PurchaseStatus.canceled) {
          verifyCancelPurchase(purchaseDetails);
        } else if (purchaseDetails.status == PurchaseStatus.restored && !isRestoring) {
          print("订阅");
          isRestoring = true;
          verifyRestorePurchase(purchaseDetails);
        }

        if (purchaseDetails.pendingCompletePurchase) {
          await InAppPurchase.instance.completePurchase(purchaseDetails);
          dispose();
        }
      }
    }
  }

  void verifyPendingPurchase(PurchaseDetails purchaseDetails) {}

  void verifyCancelPurchase(PurchaseDetails purchaseDetails) {
    sendError(AgilePayCode.payCodeCancelError,
        AgilePayCode.getMessageByCode(AgilePayCode.payCodeCancelError));
  }

  void verifyErrorPurchase(PurchaseDetails purchaseDetails) {
    sendError(AgilePayCode.payCodePayError,
        AgilePayCode.getMessageByCode(AgilePayCode.payCodePayError));
  }

  void verifySuccessPurchase(PurchaseDetails purchaseDetails) {
    sendPaySuccess(purchaseDetails.verificationData.serverVerificationData);
  }

  void verifyRestorePurchase(PurchaseDetails purchaseDetails) {
    sendRestoreSuccess(purchaseDetails.verificationData.serverVerificationData);
  }
}
