import 'dart:convert'; import 'package:collection/collection.dart'; import 'package:fluffychat/pangea/config/environment.dart'; import 'package:fluffychat/pangea/controllers/subscription_controller.dart'; import 'package:fluffychat/pangea/network/requests.dart'; import 'package:fluffychat/pangea/utils/error_handler.dart'; import 'package:fluffychat/pangea/utils/subscription_app_id.dart'; import 'package:fluffychat/widgets/matrix.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import '../network/urls.dart'; class SubscriptionRepo { static Future getAppIds() async { try { final Requests req = Requests( choreoApiKey: Environment.choreoApiKey, accessToken: MatrixState.pangeaController.userController.accessToken, ); final http.Response res = await req.get( url: PApiUrls.rcAppsChoreo, ); return SubscriptionAppIds.fromJson( jsonDecode(res.body), ); } catch (err) { ErrorHandler.logError( m: "Failed to fetch app information for revenuecat API", s: StackTrace.current, data: {}, ); return null; } } static Future?> getAllProducts() async { try { final Requests req = Requests( choreoApiKey: Environment.choreoApiKey, accessToken: MatrixState.pangeaController.userController.accessToken, ); final http.Response res = await req.get( url: PApiUrls.rcProductsChoreo, ); final Map json = jsonDecode(res.body); final RCProductsResponseModel resp = RCProductsResponseModel.fromJson(json); return resp.allProducts; } catch (err, s) { ErrorHandler.logError( e: err, s: s, data: {}, ); return null; } } static Future getCurrentSubscriptionInfo( String? userId, List? allProducts, ) async { final Requests req = Requests( choreoApiKey: Environment.choreoApiKey, accessToken: MatrixState.pangeaController.userController.accessToken, ); final http.Response res = await req.get(url: PApiUrls.rcSubscription); final Map json = jsonDecode(res.body); final RCSubscriptionResponseModel resp = RCSubscriptionResponseModel.fromJson( json, allProducts, ); return resp; } } class RCProductsResponseModel { List allProducts; RCProductsResponseModel({ required this.allProducts, }); factory RCProductsResponseModel.fromJson( Map json, ) { final List offerings = json["items"] as List; final res = offerings .map((offering) => SubscriptionDetails.fromJson(offering)) .toList() .cast(); return RCProductsResponseModel(allProducts: res); } static List productsFromPackageDetails( Map packageDetails, String packageId, Map metadata, ) { return packageDetails['products']['items'] .map( (productDetails) => SubscriptionDetails( price: double.parse(metadata['$packageId.price']), duration: SubscriptionDuration.values.firstWhereOrNull( (duration) => duration.value == metadata['$packageId.duration'], ), id: productDetails['product']['store_identifier'], appId: productDetails['product']['app_id'], ), ) .toList() .cast(); } } class RCSubscriptionResponseModel { String? currentSubscriptionId; SubscriptionDetails? currentSubscription; DateTime? expirationDate; List? allEntitlements; RCSubscriptionResponseModel({ this.currentSubscriptionId, this.currentSubscription, this.allEntitlements, this.expirationDate, }); factory RCSubscriptionResponseModel.fromJson( Map json, List? allProducts, ) { final List activeEntitlements = RCSubscriptionResponseModel.getActiveEntitlements(json); if (activeEntitlements.length > 1) { debugPrint( "User has more than one active entitlement. This shouldn't happen", ); } if (activeEntitlements.isEmpty) { debugPrint("User has no active entitlements"); return RCSubscriptionResponseModel(); } final String currentSubscriptionId = activeEntitlements[0]; final Map currentSubscriptionMetadata = json['subscriptions'][currentSubscriptionId]; final DateTime expirationDate = DateTime.parse( currentSubscriptionMetadata['expires_date'], ); final String currentSubscriptionPeriodType = currentSubscriptionMetadata['period_type'] ?? ""; final SubscriptionDetails? currentSubscription = allProducts?.firstWhereOrNull( (SubscriptionDetails sub) => sub.id.contains(currentSubscriptionId) || currentSubscriptionId.contains(sub.id), ); if (currentSubscriptionPeriodType == "trial") { currentSubscription?.makeTrial(); } return RCSubscriptionResponseModel( currentSubscription: currentSubscription, currentSubscriptionId: currentSubscriptionId, expirationDate: expirationDate, allEntitlements: activeEntitlements, ); } static List getActiveEntitlements(Map json) { return json['entitlements'] .entries .where( (MapEntry entitlement) => DateTime.parse( entitlement.value['expires_date'], ).isAfter(DateTime.now()), ) .map( (MapEntry entitlement) => entitlement.value['product_identifier'], ) .cast() .toList(); } static List getAllEntitlements(Map json) { return json['entitlements'] .entries .map( (MapEntry entitlement) => entitlement.value['product_identifier'], ) .cast() .toList(); } }