part of '../guru_analytics.dart';

/// Created by Haoyi on 2022/3/12
typedef AdjustEventConverter = AdjustEvent Function(Map<String, dynamic>);

class AdjustProfile {
  final String appToken;
  final Map<String, AdjustEventConverter> eventNameMapping;

  final bool isEnabled;

  AdjustProfile({required this.appToken, required this.eventNameMapping})
      : isEnabled = appToken.isNotEmpty;

  static AdjustEvent createAdjustEvent(String eventToken, Map<String, dynamic> params) {
    final adjustParams = Map.of(params);
    final revenue = adjustParams.remove("revenue");
    final currency = adjustParams.remove("currency");
    final event = AdjustEvent(eventToken);
    if (revenue is num && currency is String) {
      event.setRevenue(revenue, currency);
    }
    for (var entry in adjustParams.entries) {
      event.addCallbackParameter(entry.key, entry.value.toString());
    }
    return event;
  }
}

mixin AdjustAware on Analytics {
  static final List<AdjustEvent> pendingAdjustEvents = [];

  //
  static bool initializedAdjust = false;

  bool get enabledAdjust => GuruApp.instance.adjustProfile.isEnabled;

  static AdjustConfig _defaultAdjustConfigComposition(AdjustConfig adjustConfig) {
    return adjustConfig;
  }

  static AdjustConfig Function(AdjustConfig) adjustConfigComposition =
      _defaultAdjustConfigComposition;

  static AdjustConfig buildAdjustConfig() {
    final AdjustConfig config = AdjustConfig(GuruApp.instance.adjustProfile.appToken,
        kReleaseMode ? AdjustEnvironment.production : AdjustEnvironment.sandbox);
    config.fbAppId = GuruApp.instance.details.facebookAppId;
    return adjustConfigComposition(config);
  }

  Future initAdjust() async {
    if (enabledAdjust) {
      await _setupAdjustSessionCall();
      final adjustConfig = buildAdjustConfig();
      Adjust.start(adjustConfig);
      initializedAdjust = true;
      _trackAllPendingAdjustEvent();

      final adId = await Adjust.getAdid();
      if (adId != null) {
        GuruAnalytics.instance.setAdjustId(adId);
        Log.d("initAdjust adId:$adId");
      } else {
        // https://github.com/adjust/react_native_sdk/issues/90
        Log.d("adjustId is null! waiting 3s..and retry");
        Future.delayed(const Duration(seconds: 3), () async {
          final adId = await Adjust.getAdid();
          if (adId != null) {
            GuruAnalytics.instance.setAdjustId(adId);
            Log.d("initAdjust adId:$adId");
          } else {
            Log.d("initAdjust adId is null");
          }
        });
      }

      final googleAdId = await Adjust.getGoogleAdId();
      if (googleAdId != null) {
        GuruAnalytics.instance.setAdId(googleAdId);
        Log.d("initAdjust googleAdId:$googleAdId");
      }

      final idfa = Platform.isIOS ? await Adjust.getIdfa() : null;
      if (idfa != null) {
        GuruAnalytics.instance.setIdfa(idfa);
        Log.d("initAdjust idfa:$idfa");
      }
    }
  }

  // 接入Adjust后trackAdRevenueNew要放开
  void loadAdjustAdRevenue(ImpressionData impressionData) {
    if (enabledAdjust) {
      AdjustAdRevenue adRevenue = AdjustAdRevenue(AdjustConfig.AdRevenueSourceAppLovinMAX);
      adRevenue.setRevenue(impressionData.publisherRevenue, "USD");
      adRevenue.adRevenueNetwork = impressionData.networkName;
      adRevenue.adRevenueUnit = impressionData.unitId;
      adRevenue.adRevenuePlacement = impressionData.networkPlacementId;
      Adjust.trackAdRevenueNew(adRevenue);
      recordEvents("[Adjust]trackAdRevenue", adRevenue.toMap);
    }
  }

//
  Future _setupAdjustSessionCall() async {
    try {
      final deviceId = await AppProperty.getInstance().getDeviceId();
      Adjust.addSessionCallbackParameter("device_id", deviceId);
    } catch (error, stacktrace) {
      Log.e("setupAdjustSessionCall error $error, $stacktrace");
    }

    final appInstanceId = await getAppInstanceId();
    Log.d("setupAdjustSessionCall $appInstanceId");
    Adjust.addSessionCallbackParameter("user_pseudo_id", appInstanceId);
  }

  void logAdjust(String eventName,
      {String? itemCategory,
      String? itemName,
      double? value,
      Map<String, dynamic> parameters = const {}}) {
    if (enabledAdjust) {
      Map<String, dynamic> map = Map<String, dynamic>.from(parameters);
      if (itemCategory != null) {
        map["item_category"] = itemCategory;
      }
      if (itemName != null) {
        map["item_name"] = itemName;
      }
      if (value != null) {
        map["value"] = value;
      }
      _logAdjustEvent(eventName, map);
    }
  }

  void _trackAdjustEvent(AdjustEvent adjustEvent) {
    if (!enabledAdjust) {
      return;
    }
    if (!initializedAdjust) {
      pendingAdjustEvents.add(adjustEvent);
      Log.d("adjust not initialized!");
      return;
    }
    if (EventLogger.dumpLog || kDebugMode) {
      Log.d("[adjust] ${adjustEvent.toMap}");
    }
    if (pendingAdjustEvents.isNotEmpty) {
      final events = List.of(pendingAdjustEvents);
      pendingAdjustEvents.clear();
      for (var event in events) {
        Adjust.trackEvent(event);
        if (EventLogger.dumpLog || kDebugMode) {
          Log.d("[adjust] ${event.toMap}");
        }
      }
    }
    Adjust.trackEvent(adjustEvent);
  }

  void _trackAllPendingAdjustEvent() {
    if (!enabledAdjust) {
      return;
    }
    final events = List.of(pendingAdjustEvents);
    pendingAdjustEvents.clear();
    for (var event in events) {
      Adjust.trackEvent(event);
      if (EventLogger.dumpLog || kDebugMode) {
        Log.d("[adjust] ${event.toMap}");
      }
    }
  }

  AdjustEventConverter? getAdjustEventConverter(String eventName) {
    return GuruAnalyticsStrategy.instance.getAdjustEventConverter(eventName) ??
        GuruApp.instance.adjustProfile.eventNameMapping[eventName];
  }

//
  void _logAdjustEvent(String eventName, Map<String, dynamic> parameters) {
    if (!enabledAdjust) {
      return;
    }
    final AdjustEventConverter? adjustEventConverter = getAdjustEventConverter(eventName);
    if (adjustEventConverter != null) {
      AdjustEvent adjustEvent = adjustEventConverter(parameters);
      Log.d("adjustEvent:${adjustEvent.toMap}");
      _trackAdjustEvent(adjustEvent);
    }
  }
}
