import 'package:guru_app/financial/asset/assets_model.dart';
import 'package:guru_app/financial/asset/assets_store.dart';
import 'package:guru_app/financial/financial_manager.dart';
import 'package:guru_app/financial/iap/iap_manager.dart';
import 'package:guru_app/financial/iap/iap_model.dart';
import 'package:guru_app/financial/igb/igb_manager.dart';
import 'package:guru_app/financial/igb/igb_product.dart';
import 'package:guru_app/financial/igc/igc_manager.dart';
import 'package:guru_app/financial/igc/igc_model.dart';
import 'package:guru_app/financial/product/product_store.dart';
import 'package:guru_app/financial/reward/reward_manager.dart';
import 'package:guru_app/financial/reward/reward_model.dart';
import 'package:guru_app/guru_app.dart';
import 'package:guru_app/inventory/db/inventory_database.dart';
import 'package:guru_app/inventory/inventory_manager.dart';
import 'package:guru_app/test/test_guru_app_creator.dart';
import 'package:guru_utils/collection/collectionutils.dart';
import 'package:guru_utils/datetime/datetime_utils.dart';
import 'package:guru_utils/extensions/extensions.dart';
import 'package:guru_utils/controller/controller.dart';

/// Created by Haoyi on 2022/4/7

mixin AssetsAware on LifecycleController {
  final BehaviorSubject<ProductStore<IapProduct>> _productStoreSubject =
      BehaviorSubject.seeded(ProductStore());

  ProductStore<IapProduct> get currentProductStore => _productStoreSubject.value;

  AssetsStore<Asset> get currentIapAssetStore => IapManager.instance.purchasedStore;

  AssetsStore<Asset> get currentRewardedStore => RewardManager.instance.rewardedStore;

  Stream<ProductStore<IapProduct>> get observableProductStore => _productStoreSubject.stream;

  Stream<AssetsStore<Asset>> get observableIapPurchased => IapManager.instance.observableAssetStore;

  Stream<AssetsStore<Asset>> get observableRewarded => RewardManager.instance.observableAssetStore;

  Stream<AssetsStore<Asset>> get observableAssets => FinancialManager.instance.observableAssets;

  int _latestRefreshIapProductTimestamp = 0;

  bool get isIapCanceled => IapManager.instance.latestIapCause == IapCause.canceled;

  bool get isIapError => IapManager.instance.latestIapCause == IapCause.error;

  int get currentIgcBalance => IgcManager.instance.currentBalance;

  Stream<int> get observableIgcBalance => IgcManager.instance.observableCurrentBalance;

  Stream<Map<String, InventoryItem>> get observableInventoryItems =>
      InventoryManager.instance.observableData;

  Future restorePurchases() async {
    return await IapManager.instance.restorePurchases();
  }

  Future clearIapAssets() async {
    return await IapManager.instance.clearAssetRecord();
  }

  void observeIapProducts(Set<TransactionIntent> intents) {
    addSubscription(IapManager.instance.observableProductDetails.listen((details) async {
      final productStore = await IapManager.instance.buildProducts(intents);
      _productStoreSubject.addEx(productStore);
    }));
  }

  void refreshIapProducts() async {
    final now = DateTimeUtils.currentTimeInMillis();
    if (now - _latestRefreshIapProductTimestamp > DateTimeUtils.minuteInMillis) {
      IapManager.instance.refreshProducts();
      _latestRefreshIapProductTimestamp = now;
    } else {
      Log.w("refreshIapProducts Too Frequency!", tag: "IAP");
    }
  }

  Future<RewardProduct> buildRewardProduct(TransactionIntent intent) {
    return RewardManager.instance.buildRewardProduct(intent);
  }

  Future<IgbProduct> buildIgbProduct(TransactionIntent intent) {
    return IgbManager.instance.buildIgbProduct(intent);
  }

  int getInventoryBalance(String sku) {
    return InventoryManager.instance.getData(sku)?.balance ?? 0;
  }

  TimeSensitiveData getInventoryTimeSensitiveData(String sku) {
    return InventoryManager.instance.getData(sku)?.timeSensitive ?? const TimeSensitiveData();
  }

  /// 使用指定[sku]的道具，[amount]为使用数量，[action]的行为，[scene]为使用场景
  /// useProp最终会得到一个行为上的收益，因此这里为了方便针对道具使用进行统一的行为分析
  /// 这里的 [action]和[scene]最终会通过 spend_virtual_currency 事件进行统一的统计
  /// propCategory可以参照 [PropCategory] 中的定义
  /// 具体参数对照如下：
  ///   - **`item_name`**: [intent] 如果这里指定了使用道具的意图，那么这里就会使用这个意图，否则使用场景,
  ///   - **`item_category`**: [category],
  ///   - **`virtual_currency_name`**: [propSku],
  ///   - **`value`**: [amount],
  ///   - **`balance`**: balance,
  ///   - **`scene`**: [scene],
  ///   - **`level_name`**: levelName
  ///
  ///  返回值为是否成功使用道具,false表示道具不足,true表示使用成功
  ///
  Future<bool> useProp(
    String propSku,
    String scene, {
    int amount = 1,
    String? intent,
    String category = PropCategory.boosts,
    bool timeSensitiveOnly = false,
    int? transactionTs,
  }) async {
    final manifest = Manifest.action(category, scene,
        extras: CollectionUtils.filterOutNulls({
          ExtraReservedField.contentId: intent ?? scene, // 如果这里指定了使用道具的意图，那么这里就会使用这个意图，否则使用场景
          ExtraReservedField.transactionTs: transactionTs // 如果这里指定了交易时间，那么就会使用这个时间，否则使用当前时间
        }));
    return await InventoryManager.instance.consume(
        [StockItem.consumable(propSku, amount)], manifest,
        timeSensitiveOnly: timeSensitiveOnly);
  }

  Future<bool> requestProduct(Product product, {String from = ""}) async {
    if (product is IapProduct) {
      return await IapManager.instance.buy(product);
    } else if (product is IgcProduct) {
      return await IgcManager.instance.purchase(product);
    } else if (product is RewardProduct) {
      return await RewardManager.instance.claim(product);
    } else if (product is IgbProduct) {
      return await IgbManager.instance.redeem(product);
    } else {
      return false;
    }
  }
}
