import 'package:flutter/cupertino.dart';
import 'package:synchronized/synchronized.dart';

import '../../data/bean/payment_way.dart';
import '../../data/bean/store_item.dart';
import '../../data/repositories/store_repository.dart';
import '../../utils/async_util.dart';

class PaymentStatusManager {
  PaymentStatusManager._();

  //订单状态
  //0-查询失败，继续轮询
  //1-未支付，继续轮询
  //2-支付成功
  //3-支付关闭
  //4-已退款
  static const int payStatusFail = 0;
  static const int payStatusUnpaid = 1;
  static const int payStatusSuccess = 2;
  static const int payStatusClose = 3;
  static const int payStatusRefund = 4;

  final Map<String, PaymentStatusCallback> callbackMap = {};
  final Map<String, CancelableFuture> pollingSubscriptionMap = {};
  final _lock = Lock();

  void _startCheckPolling(
      String orderNo, PaymentWay paymentWay, StoreItem storeItemBean,
      {String? receiptData}) async {
    await _lock.synchronized(() async {
      pollingSubscriptionMap[orderNo]?.cancel();
      debugPrint('开始轮询支付状态: orderNo = $orderNo');
      CancelableFuture orderFuture = AsyncUtil.retryWithExponentialBackoff(
              () {
            return storeRepository
                .orderStatus(orderNo, receiptData: receiptData)
                .then((status) {
              if (status == payStatusSuccess) {
                return true;
              } else {
                throw PaymentStatusException(status);
              }
            });
          },
          10,
          predicate: (error) {
            if (error is PaymentStatusException) {
              return error.status == payStatusFail ||
                  error.status == payStatusUnpaid;
            }
            return true;
          });
      orderFuture.then((data) async {
        debugPrint('支付成功: orderNo = $orderNo');
        // accountRepository.refreshUserInfo();
        await _lock.synchronized(() {
          callbackMap[orderNo]
              ?.onPaymentSuccess(orderNo, paymentWay, storeItemBean);
          callbackMap.remove(orderNo);
        });
        reportPaySuccess(storeItemBean.amount, orderNo, storeItemBean.name,
            paymentWay.payMethod);
      }).catchError((error) async {
        debugPrint('支付失败: orderNo = $orderNo, error = $error');
        await _lock.synchronized(() {
          callbackMap[orderNo]
              ?.onPaymentError(error);
          callbackMap.remove(orderNo);
        });
      });
      pollingSubscriptionMap[orderNo] = orderFuture;
    });
  }

  void reportPaySuccess(
      int price, String orderId, String itemName, int paymentWay) {
    // EventHandler.reportPay(price, orderId, itemName, paymentWay);
  }

  void checkPaymentStatus(
      String orderNo, PaymentWay paymentWay, StoreItem storeItemBean,
      {String? receiptData}) {
    // recordKeyInfoToDisk(orderNo, paymentWay, storeItemBean);
    _startCheckPolling(orderNo, paymentWay, storeItemBean,
        receiptData: receiptData);
  }

  void registerPaymentSuccessCallback(
      String orderNo, PaymentStatusCallback callback) async {
    await _lock.synchronized(() {
      callbackMap[orderNo] = callback;
    });
  }

  void unregisterPaymentSuccessCallback(PaymentStatusCallback callback) async {
    await _lock.synchronized(() {
      callbackMap.removeWhere((key, value) => value == callback);
    });
  }
}

class PaymentStatusException implements Exception {
  final int status;

  PaymentStatusException(this.status);

  @override
  String toString() {
    return '支付状态异常: status = $status';
  }
}

abstract class PaymentStatusCallback {
  void onPaymentSuccess(
      String orderNo, PaymentWay paymentWay, StoreItem storeItemBean);

  void onPaymentError(Error error);
}

final paymentStatusManager = PaymentStatusManager._();
