import 'dart:async';

import 'package:flutter/widgets.dart';
import 'package:gravity_engine/gravity_engine.dart';
import 'package:gravity_engine/gravity_engine_method_channel.dart';
import 'package:location/data/repositories/account_repository.dart';
import 'package:location/data/repositories/config_repository.dart';
import 'package:location/utils/atmob_log.dart';
import '../../data/api/response/member_status_response.dart';
import '../../data/consts/build_config.dart';
import '../../data/consts/payment_type.dart';
import '../../device/atmob_platform_info.dart';
import '../../utils/async_util.dart';
import '../../utils/mmkv_util.dart';

typedef GravitySuccessCallback = void Function();

class GravityHelper {
  static const String tag = 'GravityHelper';
  static const String _keyCurrentDeviceId = "current_device_id";
  static CancelableFuture<bool>? _initFuture;
  static String? _currentClientId;

  static bool? _isFromPromote;

  static init() {
    _initialize(false);
    _uploadClientId();
  }

  static _uploadClientId() {
    AsyncUtil.retryWithExponentialBackoff<void>(() async {
      String deviceId = await _getDeviceId(false);
      ConfigRepository.getInstance().uploadClientId(deviceId);
    }, 5)
        .then((_) {
      AtmobLog.d(tag, 'gravity uploadClientId success');
    }).catchError((error) {
      AtmobLog.d(tag, 'gravity uploadClientId error:$error');
    });
  }

  static _initialize(bool refreshDeviceId,
      {GravitySuccessCallback? callback}) async {
    _initFuture?.cancel();
    _initFuture = AsyncUtil.retryWithExponentialBackoff<bool>(() async {
      String deviceId = await _getDeviceId(refreshDeviceId);
      CancelableFuture<bool> initFuture = _gravityInitialize(deviceId);
      _initFuture = initFuture;
      return await initFuture;
    }, 5);
    _initFuture?.then((isPromote) {
      _isFromPromote = isPromote;
      callback?.call();
    }).catchError((error) {
      _initialize(refreshDeviceId, callback: callback);
    });
  }

  //目前返回deviceId
  static Future<String> _getDeviceId(bool refreshDeviceId) async {
    String? currentDeviceId = _getCurrentDeviceId();
    if (currentDeviceId == null || refreshDeviceId) {
      MemberStatusResponse response =
          await AccountRepository.getInstance().getMemberStatus();
      KVUtil.putString(_keyCurrentDeviceId, response.deviceId);
      return response.deviceId;
    }
    return currentDeviceId;
  }

  static String? _getCurrentDeviceId() {
    return KVUtil.getString(_keyCurrentDeviceId, null);
  }

  static CancelableFuture<bool> _gravityInitialize(String deviceId) {
    return AsyncUtil.retryWithExponentialBackoff<bool>(() {
      return GravityEngine.initialize(
              GravityConfig.gravityAppId,
              GravityConfig.gravityAccessToken,
              deviceId,
              atmobPlatformInfo.channelName ?? '',
              BuildConfig.isDebug)
          .then((data) {
        debugPrint('gravity initialize($deviceId) success');
        GravityHelper._currentClientId = deviceId;
        return data;
      });
    }, 5);
  }

  static void onLogin() {
    _clearCurrentDeviceId();
    _initialize(true, callback: () {
      if (_currentClientId != null) {
        GravityEngine.login(_currentClientId!);
      }
    });
  }

  static void onLogout() async {
    _currentClientId = null;
    await GravityEngine.logout();
    _initialize(false, callback: null);
  }

  static void _clearCurrentDeviceId() {
    KVUtil.putString(_keyCurrentDeviceId, null);
  }

  static bool? getIsFromPromote() {
    return _isFromPromote;
  }

  static void report(String eventId, {Map<String, dynamic>? params}) {
    GravityEngine.trackEvent(eventId, eventProperties: params);
  }

  static void reportPay(
      int payAmount, String orderNo, String productName, int payWay) {
    PayType payType;
    if (payWay == PayMethod.alipay) {
      payType = PayType.alipay;
    } else if (payWay == PayMethod.wechat) {
      payType = PayType.wechat;
    } else if (payWay == PayMethod.apple) {
      payType = PayType.apple;
    } else {
      payType = PayType.unknown;
    }
    GravityEngine.trackPay(
        orderNo, productName, payAmount, Currency.cny, payType);
  }
}
