import 'dart:async';
import 'dart:io';

import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/product.dart';
import 'package:aitrainer_app/service/logging.dart';
import 'package:flutter_inapp_purchase/flutter_inapp_purchase.dart';

class PlatformPurchaseApi with Logging {
  static final PlatformPurchaseApi _singleton = PlatformPurchaseApi._internal();

  StreamSubscription _purchaseUpdatedSubscription;
  StreamSubscription _purchaseErrorSubscription;
  StreamSubscription _conectionSubscription;
  String _platformVersion = 'Unknown';
  List<IAPItem> _items = [];
  List getIAPItems() => _items;
  List<PurchasedItem> _purchases = [];

  final List<String> _productList = List();

  List getProductList() => _productList;

  /* Platform.isAndroid
      ? [
          'android.test.purchased',
          'point_1000',
          '5000_point',
          'android.test.canceled',
        ]
      : ['com.cooni.point1000', 'com.cooni.point5000'];
  */

  factory PlatformPurchaseApi() {
    return _singleton;
  }

  PlatformPurchaseApi._internal();

  Future<void> close() async {
    if (_conectionSubscription != null) {
      _conectionSubscription.cancel();
      _conectionSubscription = null;
    }
    await FlutterInappPurchase.instance.endConnection;
  }

  // Platform messages are asynchronous, so we initialize in an async method.
  Future<void> initPurchasePlatformState() async {
    if (_productList.length > 0) {
      return;
    }
    log(" --- Init PurchasePlatform");
    String platformVersion;
    // Platform messages may fail, so we use a try/catch PlatformException.
    try {
      platformVersion = await FlutterInappPurchase.instance.platformVersion;
    } on Exception {
      platformVersion = 'Failed to get platform version for InAppPurchase.';
      log("PlatformVersion" + platformVersion);
    }

    // prepare
    var result = await FlutterInappPurchase.instance.initConnection;
    log(' FlutterInappPurchase init result: $result');

    _platformVersion = platformVersion;

    // refresh items for android
    try {
      String msg = await FlutterInappPurchase.instance.consumeAllItems;
      log('consumeAllItems: $msg');
    } catch (err) {
      log('consumeAllItems error: $err');
    }

    _conectionSubscription = FlutterInappPurchase.connectionUpdated.listen((connected) {
      log('connected: $connected');
    });

    _purchaseUpdatedSubscription = FlutterInappPurchase.purchaseUpdated.listen((productItem) {
      log('purchase-updated: $productItem');
    });

    _purchaseErrorSubscription = FlutterInappPurchase.purchaseError.listen((purchaseError) {
      log('purchase-error: $purchaseError');
    });

    getSubscriptions();
  }

  void getSubscriptions() {
    Cache().products.forEach((element) {
      Product product = element as Product;
      if (Platform.isAndroid) {
        if (product.productIdAndroid != null && product.productIdAndroid.isNotEmpty) {
          _productList.add(product.productIdAndroid);
        }
      } else {
        if (product.productIdIos != null && product.productIdIos.isNotEmpty) {
          _productList.add(product.productIdIos);
        }
      }
    });

    _productList.forEach((element) {
      print(element);
    });
    _getSubscription();
  }

  void purchase(Product product) {
    if (product == null) {
      throw Exception("No product to purchase");
    }
    String productId = Platform.isAndroid ? product.productIdAndroid : product.productIdIos;
    IAPItem selected;
    for (var item in _items) {
      if (item.productId == productId) {
        selected = item;
        log("Item to purchase: " + item.toString());
      }
    }

    if (selected != null) {
      requestPurchase(selected);
    } else {
      throw Exception("product " + productId + " not defined in the PlatformStore");
    }
  }

  void requestPurchase(IAPItem item) {
    //FlutterInappPurchase.instance.requestPurchase(item.productId);
    FlutterInappPurchase.instance.requestPurchase(item.productId);
  }

  Future _getSubscription() async {
    List<IAPItem> items = await FlutterInappPurchase.instance.getSubscriptions(_productList);
    for (var item in items) {
      log('${item.toString()}');
      this._items.add(item);
    }

    this._items = items;
    this._purchases = [];
  }

  Future _getPurchases() async {
    List<PurchasedItem> items = await FlutterInappPurchase.instance.getAvailablePurchases();
    for (var item in items) {
      log('${item.toString()}');
      this._purchases.add(item);
    }

    this._items = [];
    this._purchases = items;
  }

  Future _getPurchaseHistory() async {
    List<PurchasedItem> items = await FlutterInappPurchase.instance.getPurchaseHistory();
    for (var item in items) {
      log('${item.toString()}');
      this._purchases.add(item);
    }

    this._items = [];
    this._purchases = items;
  }
}