import 'package:flutter/cupertino.dart';
import 'package:injectable/injectable.dart';
import 'package:location/data/bean/goods_bean.dart';
import 'package:location/data/bean/pay_item_bean.dart';
import 'package:location/data/repositories/member_repository.dart';
import 'package:synchronized/synchronized.dart';

import '../data/api/response/order_first_check_response.dart';
import '../di/get_it.dart';
import '../handler/event_handler.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 MemberRepository memberRepository;

  PaymentStatusManager(this.memberRepository);

  static PaymentStatusManager getInstance() {
    return getIt.get<PaymentStatusManager>();
  }

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

  void _startCheckPolling(
      String orderNo, PayItemBean paymentWay, GoodsBean storeItemBean,
      {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, paymentWay, storeItemBean);
          callbackMap.remove(orderNo);
        });
        reportPaySuccess(storeItemBean.amount, orderNo, storeItemBean.name,
            paymentWay.payMethod);
      }).catchError((error) async {
        ///失败回调
        callbackMap[orderNo]?.onPaymentFail();
        await _lock.synchronized(() {
          callbackMap.remove(orderNo);
        });
        debugPrint('支付失败: orderNo = $orderNo, error = $error');
      });
      pollingSubscriptionMap[orderNo] = orderFuture;
    });
  }

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

  ///检查是否是第一次支付
  Future<OrderFirstCheckResponse> onOrderFirstCheck() {
    return memberRepository.
    orderFirstCheck()
    .then((checkResponse) {
      return checkResponse;
    });
  }

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

  void checkPaymentStatus(
      String orderNo, PayItemBean paymentWay, GoodsBean storeItemBean,
      {String? receiptData}) {
    final way = paymentWay.copyWith();
    final goods = storeItemBean.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, PayItemBean paymentWay, GoodsBean storeItemBean);

  void onPaymentFail();
}
