import 'dart:io';

import 'package:guru_app/financial/data/db/order_database.dart';
import 'package:guru_app/financial/igb/igb_product.dart';
import 'package:guru_app/financial/manifest/manifest.dart';
import 'package:guru_app/financial/manifest/manifest_manager.dart';
import 'package:guru_app/guru_app.dart';
import 'package:guru_app/inventory/inventory_manager.dart';
import 'package:guru_utils/hash/hash.dart';
import 'package:in_app_purchase/in_app_purchase.dart';
import 'package:guru_app/financial/iap/iap_model.dart';
import 'package:guru_app/financial/igc/igc_model.dart';
import 'package:guru_app/financial/reward/reward_model.dart';

part 'product_profile.dart';

/// Created by Haoyi on 6/1/21

class OrderMethods {
  static const free = 0;
  static const gem = 1; // 宝石购买
  static const iap = 2; // IAP购买
  static const reward = 3; // 奖励收获
  static const limit = 4;

  static String toAbbrevText(int method) {
    switch (method) {
      case free:
        return "free";
      case gem:
        return "gem";
      case iap:
        return "iap";
      case reward:
        return "reward";
      case limit:
        return "limit";
      default:
        return "";
    }
  }
}

class OrderStates {
  static const init = 0;
  static const success = 1;
  static const pending = -1;
  static const error = -2;
}

class TransactionAttributes {
  static const unknown = 0;

  // Offer products for sale in your app for a one-off charge
  @deprecated
  static const possessive = DetailsAttr.permanent;
  static const asset = DetailsAttr.permanent;
  static const consumable = DetailsAttr.consumable;

  static const Set<int> oneOffChargeAttributes = <int>{asset, consumable};

  // Subscriptions are in-app content or services that are billed to users on a recurring basis
  static const subscriptions = 10;

  static const count = 11;
}

class TransactionCurrency {
  static const free = "_FVC"; // Free Virtual Currency
  static const igc = "_IGC"; // In-Game Virtual Currency
  static const reward = "_RVC"; // Reward Virtual Currency
}

// 这里的配置有别于 GP 上的配置，由于 GP 上对应的配置无法满足我们的需求，所以我们需要自己定义一套配置
enum EligibilityCriteria {
  // 这里对应的是 GP 上的 NEW CUSTOMER，但是新用户的判断是以APP的生命周期为标准，
  // 没有购买过此商品组的新用户(默认选项)
  newCustomerNeverHadSubscribedThisGroup,

  // 这里对应的是 GP 上的 NEW CUSTOMER，但是新用户的判断是以APP的生命周期为标准，
  // 没有购买过此商品的新用户
  newCustomerNeverHadThisSubscription,

  // 这里对应的是 GP 上的 NEW CUSTOMER，但是新用户的判断是以APP的生命周期为标准，
  // 没有购买过任何订阅商品的新用户
  newCustomerNeverHadAnySubscription,

  // 依赖 ProductId 进行筛选
  dependencyProductId
}

class ProductId {
  final String android;
  final String ios;
  final int attr;

  // android only
  final String? basePlan;
  final String? offerId;
  final bool points;

  final ProductId? _originId;

  bool get isConsumable => attr == TransactionAttributes.consumable;

  bool get hasOffer =>
      Platform.isAndroid && basePlan?.isNotEmpty == true && offerId?.isNotEmpty == true;

  bool get hasBasePlan => Platform.isAndroid && basePlan?.isNotEmpty == true;

  static final _iapEventRegExp = RegExp(r'^.*\.[ia]\.');

  ProductId get originId => _originId ?? this;

  @override
  String toString() {
    if (hasOffer) {
      return 'ProductId{sku: $sku, basePlan: $basePlan, offerId: $offerId}';
    }
    return 'ProductId{android: $android, ios: $ios, attr: $attr, points:$points}';
  }

  @deprecated
  bool get isPossessive => attr == TransactionAttributes.asset;

  bool get isAsset => attr == TransactionAttributes.asset;

  bool get isPoints => points;

  bool get isOneOffCharge =>
      (attr == TransactionAttributes.consumable) || (attr == TransactionAttributes.asset);

  bool get isSubscription => attr == TransactionAttributes.subscriptions;

  String get iapEventName => sku.replaceFirst(_iapEventRegExp, "iap.").replaceAll(".", "_");

  String get sku => Platform.isIOS ? ios : android;

  static const ProductId invalid =
      ProductId.fromSku(sku: "", attr: TransactionAttributes.consumable);

  const ProductId(
      {required this.android,
      required this.ios,
      required this.attr,
      this.basePlan,
      this.offerId,
      this.points = false,
      ProductId? originId})
      : _originId = originId;

  const ProductId.fromSku(
      {required String sku, required this.attr, this.basePlan, this.offerId, this.points = false})
      : android = sku,
        ios = sku,
        _originId = null;

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is ProductId &&
          runtimeType == other.runtimeType &&
          sku == other.sku &&
          attr == other.attr &&
          basePlan == other.basePlan &&
          offerId == other.offerId &&
          points == points;

  @override
  int get hashCode => hashObjects([sku, attr, basePlan ?? '', offerId ?? '', points]);

  bool isValid() {
    return sku.isNotEmpty;
  }

  TransactionIntent createIntent(
      {required String scene,
      int igcCost = 0,
      List<StockItem> igbCost = const <StockItem>[],
      bool sales = false,
      double rate = 1.0,
      EligibilityCriteria eligibilityCriteria =
          EligibilityCriteria.newCustomerNeverHadSubscribedThisGroup}) {
    return TransactionIntent(this, scene,
        igcCost: igcCost, sales: sales, rate: rate, eligibilityCriteria: eligibilityCriteria);
  }

  Future<RewardProduct> createRewardProduct(String scene) async {
    final intent = createIntent(scene: scene);
    final manifest = await ManifestManager.instance.createManifest(intent);
    return RewardProduct(this, manifest);
  }

  Future<IgcProduct> createIgcProduct(int igcCost, String scene) async {
    final intent = createIntent(scene: scene, igcCost: igcCost);
    final manifest = await ManifestManager.instance.createManifest(intent);
    return IgcProduct(this, manifest, igcCost);
  }

  Future<IgbProduct> createIgbProduct(List<StockItem> igbCost, String scene,
      {Manifest? specified}) async {
    final manifest = specified ??
        await ManifestManager.instance.createManifest(createIntent(scene: scene, igbCost: igbCost));
    return IgbProduct(this, manifest, igbCost);
  }
}

abstract class Product {
  ProductId get productId;

  Manifest get manifest;

  factory Product.iap(ProductId productId, ProductDetails details, Manifest manifest,
      {ProductDetails? offerDetails}) = IapProduct;

  factory Product.igc(ProductId productId, Manifest manifest, int cost) = IgcProduct;

  factory Product.reward(ProductId productId, Manifest manifest) = RewardProduct;

  factory Product.igb(ProductId productId, Manifest manifest, List<StockItem> cost) = IgbProduct;

//
// factory Product.gems(ProductId productId, int price, Manifest manifest) = GemProduct;
//
// factory Product.reward(Reward reward) = RewardProduct;
//
//   OrderEntity createOrder();
}

class TransactionState {
  static const init = 0;
  static const success = 1;
  static const pending = -1;
  static const error = -2;
  static const expired = -3;
}

// 交易方式
enum TransactionMethod {
  iap, // IAP购买
  igc, // In-game currency 购买（coin/gems..)
  reward, // 奖励获得

  bonus, // 优惠
  igb, // In-game barter
  free,
  migrate,
  unknown
}

String convertTransactionMethodName(TransactionMethod method) {
  switch (method) {
    case TransactionMethod.iap:
      return "iap_buy";
    case TransactionMethod.igc:
      return "igc";
    case TransactionMethod.reward:
      return "reward";
    case TransactionMethod.bonus:
      return "bonus";
    case TransactionMethod.igb:
      return "igb";
    case TransactionMethod.free:
      return "prop";
    case TransactionMethod.migrate:
      return "migrate";
    default:
      return "unknown";
  }
}

class TransactionIntent {
  final ProductId productId;
  final int igcCost; // In-game currency cost
  final List<StockItem> igbCost; // In-game barter cost
  final String scene; // 购买场景(最终会用到logEarnVirtualCurrency的item_category上)
  final bool sales; // 是否为促销商品
  final double rate; // 默认1.0 指收益率，如:打折促销时设成1.2，最终的收益将是1.2倍
  final EligibilityCriteria eligibilityCriteria;

  TransactionIntent(this.productId, this.scene,
      {this.igcCost = 0,
      this.igbCost = const <StockItem>[],
      this.sales = false,
      this.rate = 1.0,
      this.eligibilityCriteria = EligibilityCriteria.newCustomerNeverHadSubscribedThisGroup});
}
