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

import 'package:flutter/material.dart';
import 'package:in_app_purchase/in_app_purchase.dart';
import 'package:mnemo_cards/utils/iterable_helper.dart';
import 'package:mnemo_cards_common/mnemo_cards_common.dart';
import 'package:webview_flutter/webview_flutter.dart';
import '../../di/injector.dart';
import '../../di/locator.dart';
import '../../main.dart';
import '../analytics/analytics.dart';

enum StoreItemType {
  ads,
  subscription,
  pack,
}

class InAppPurchaseService {
  final InAppPurchase _inAppPurchase = InAppPurchase.instance;
  final Stream<List<PurchaseDetails>> storeSubscription =
      InAppPurchase.instance.purchaseStream;

  InAppPurchase get instance => _inAppPurchase;

  Future<bool> buyPack(CardPackBuyDto dto) async {
    try {
      final pack = await getPackStoreProduct(dto);
      final result = await buyItemInStore(pack.first);
      return result;
    } catch (e, s) {
      log('err', error: e, stackTrace: s);
      Analytics.buyError(
        dto,
        PaymentSystem.google,
        data: {
          'e': e.toString(),
          's': s.toString(),
        },
      );
      return false;
    }
  }

  Future<bool> buyPackWithYooMoney(
      CardPackBuyDto dto, BuildContext? context) async {
    final paymentUrl =
        await locator.repository.createPayment(dto.id, PaymentSystem.yookassa);
    if (paymentUrl == null) {
      Analytics.buyError(
        dto,
        PaymentSystem.yookassa,
        message: 'payment url is null',
      );
      return false;
    }
    final controller = WebViewController()
      ..setJavaScriptMode(JavaScriptMode.unrestricted)
      ..loadRequest(Uri.parse(paymentUrl));
    return showModalBottomSheet(
      context: context ?? scaffoldKey.currentContext!,
      enableDrag: false,
      showDragHandle: true,
      useSafeArea: true,
      isScrollControlled: true,
      backgroundColor: Colors.white,
      builder: (context) {
        return Container(
          child: WebViewWidget(controller: controller),
          padding: EdgeInsets.only(
            bottom: MediaQuery.of(context).viewInsets.bottom,
          ),
        );
      },
    ).then((_) async {
      final success = await locator.repository.checkUserPayment();
      if (success) {
        Analytics.buyComplete(
          dto,
          PaymentSystem.yookassa,
        );
        locator.packUpdater.updateAvailablePacks();
        return true;
      }
      Analytics.buyError(
        dto,
        PaymentSystem.yookassa,
        message: 'payment not verified',
      );
      return false;
    });
  }

  Future<List<ProductDetails>> getPackStoreProduct(CardPackBuyDto dto) async {
    final bool isAvailable = await _inAppPurchase.isAvailable();
    if (!isAvailable) {
      Analytics.buyError(
        dto,
        PaymentSystem.google,
        message: 'in app purchase not available',
      );
      return [];
    }
    final ids = {
      if (Platform.isAndroid) dto.googlePlayId,
      if (Platform.isIOS) dto.appStoreId,
    }.whereNotNull().toSet();
    if (ids.isEmpty) {
      Analytics.buyError(
        dto,
        PaymentSystem.google,
        message: 'product id not set',
      );
      return [];
    }

    final ProductDetailsResponse productDetailResponse =
        await _inAppPurchase.queryProductDetails(ids);

    if (productDetailResponse.error != null ||
        productDetailResponse.productDetails.isEmpty) {
      Analytics.buyError(
        dto,
        PaymentSystem.google,
        data: {
          'msg': 'cant get product details ${productDetailResponse.error}',
          'not_found': productDetailResponse.notFoundIDs.join(','),
        },
      );
      return [];
    }

    return productDetailResponse.productDetails;
  }

  Future<bool> buyItemInStore(ProductDetails product) async {
    final PurchaseParam purchaseParam = PurchaseParam(productDetails: product);
    return InAppPurchase.instance
        .buyNonConsumable(purchaseParam: purchaseParam);
  }

  Future<void> completePurchase(PurchaseDetails purchaseDetails) async {
    await InAppPurchase.instance.completePurchase(purchaseDetails);
  }
}

class PurchaseDetailsStreamSubscription {
  final InAppPurchaseService inAppPurchaseService = getIt.get();

  Future<void> onPurchased(PurchaseDetails purchaseDetails) async {
    try {
      Analytics.buyEvent(
        null,
        PaymentSystem.google,
        message: 'onPurchased',
        data: {
          'status': purchaseDetails.status.name,
          'product': purchaseDetails.productID,
          'date': purchaseDetails.transactionDate,
        },
      );
      final result = await locator.repository.checkPayment(
        purchaseDetails.productID,
        purchaseDetails.verificationData.serverVerificationData,
        PaymentSystem.google,
      );
      if (result) {
        Analytics.buyComplete(
          null,
          PaymentSystem.google,
          message: purchaseDetails.productID,
        );
        log('Purchased');
      } else {
        Analytics.buyError(
          null,
          PaymentSystem.yookassa,
          message: 'payment not verified ${purchaseDetails.productID}',
        );
        throw Exception('Cant verify purchase');
      }
    } catch (e, s) {
      log(e.toString(), stackTrace: s);
    }
  }

  StreamSubscription<List<PurchaseDetails>>? _streamSubscription;

  PurchaseDetailsStreamSubscription();

  Future<void> init() async {
    _streamSubscription = inAppPurchaseService.storeSubscription.listen(
      (List<PurchaseDetails> events) {
        Future.forEach(
          events,
          (PurchaseDetails purchaseDetails) async {
            if (purchaseDetails.pendingCompletePurchase ||
                purchaseDetails.status == PurchaseStatus.purchased) {
              onPurchased(purchaseDetails);
            }
          },
        );
      },
    );
  }

  void close() {
    _streamSubscription?.cancel();
  }
}
