import 'package:flutter/cupertino.dart';
import 'package:injectable/injectable.dart';
import 'package:keyboard/data/bean/goods_info.dart';
import 'package:keyboard/data/bean/pay_way_info.dart';
import 'package:keyboard/data/repository/store_repository.dart';

import 'package:synchronized/synchronized.dart';


import 'async_util.dart';

class PaymentStatus {
  PaymentStatus._();

  //订单状态
  //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;
}

@lazySingleton
class PaymentStatusManager {
  final StoreRepository storeRepository;

  PaymentStatusManager(this.storeRepository);

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

  void _startCheckPolling(
      String orderNo, PayWayInfo payWayInfo, GoodsInfo goodsInfo,
      {String? receiptData}) async {
    await _lock.synchronized(() async {
      pollingSubscriptionMap[orderNo]?.cancel();
      debugPrint('开始轮询支付状态: orderNo = $orderNo');
      CancelableFuture<int> orderFuture = AsyncUtil.retry(
          () => _queryOrderStatus(orderNo, receiptData: receiptData),
          Duration(seconds: 2), predicate: (error) {
        if (error is PaymentStatusException) {
          return error.status == PaymentStatus.payStatusFail ||
              error.status == PaymentStatus.payStatusUnpaid;
        }
        return true;
      }, maxRetry: 50);
      orderFuture.then((status) async {
        debugPrint('支付成功: orderNo = $orderNo');
        await _lock.synchronized(() {
          callbackMap[orderNo]
              ?.onPaymentSuccess(orderNo, payWayInfo, goodsInfo);
          callbackMap.remove(orderNo);
        });
        reportPaySuccess(goodsInfo.amount, orderNo, goodsInfo.name,
            payWayInfo.payMethod);
      }).catchError((error) async {
        await _lock.synchronized(() {
          callbackMap.remove(orderNo);
        });
        debugPrint('支付失败: orderNo = $orderNo, error = $error');
      });
      pollingSubscriptionMap[orderNo] = orderFuture;
    });
  }

  Future<int> _queryOrderStatus(String orderNo, {String? receiptData}) {
    return storeRepository
        .orderStatus(orderNo, receiptData: receiptData)
        .then((status) async {
      if (status == PaymentStatus.payStatusSuccess) {
        return status;
      }
      throw PaymentStatusException(status);
    });
  }

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

  void checkPaymentStatus(
      String orderNo, PayWayInfo payWayInfo, GoodsInfo goodsInfo,
      {String? receiptData}) {
    final way = payWayInfo.copyWith();
    final goods = goodsInfo.copyWith();
    // recordKeyInfoToDisk(orderNo, paymentWay, storeItemBean);
    _startCheckPolling(orderNo, way, goods, 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);
    });
  }

  void removePollingSubscription(String orderNo) {
    pollingSubscriptionMap[orderNo]?.cancel();
    pollingSubscriptionMap.remove(orderNo);
    callbackMap.remove(orderNo);
  }
}

class PaymentStatusException implements Exception {
  final int status;

  PaymentStatusException(this.status);

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

abstract class PaymentStatusCallback {
  void onPaymentSuccess(
      String orderNo, PayWayInfo payWayInfo, GoodsInfo goodsInfo);
}
