import 'package:flutter/material.dart'; import '../l10n/app_localizations.dart'; import '../models/payment_card_model.dart'; import '../models/subscription_model.dart'; import '../providers/category_provider.dart'; import '../providers/payment_card_provider.dart'; import 'subscription_category_helper.dart'; enum SubscriptionGroupingMode { category, paymentCard } class SubscriptionGroupData { final String id; final String title; final List subscriptions; final SubscriptionGroupingMode mode; final PaymentCardModel? paymentCard; final bool isUnassignedCard; final String? categoryKey; final String? subtitle; const SubscriptionGroupData({ required this.id, required this.title, required this.subscriptions, required this.mode, this.paymentCard, this.isUnassignedCard = false, this.categoryKey, this.subtitle, }); } class SubscriptionGroupingHelper { static const _unassignedCardKey = '__unassigned__'; static List buildGroups({ required BuildContext context, required List subscriptions, required SubscriptionGroupingMode mode, required CategoryProvider categoryProvider, required PaymentCardProvider paymentCardProvider, }) { if (mode == SubscriptionGroupingMode.paymentCard) { return _groupByPaymentCard( context: context, subscriptions: subscriptions, paymentCardProvider: paymentCardProvider, ); } return _groupByCategory( context: context, subscriptions: subscriptions, categoryProvider: categoryProvider, ); } static List _groupByCategory({ required BuildContext context, required List subscriptions, required CategoryProvider categoryProvider, }) { final localizedMap = SubscriptionCategoryHelper.categorizeSubscriptions( subscriptions, categoryProvider, context); final orderMap = {}; for (var i = 0; i < categoryProvider.categories.length; i++) { orderMap[categoryProvider.categories[i].name] = i; } final groups = localizedMap.entries.map((entry) { final title = categoryProvider.getLocalizedCategoryName(context, entry.key); return SubscriptionGroupData( id: entry.key, title: title, subscriptions: entry.value, mode: SubscriptionGroupingMode.category, categoryKey: entry.key, ); }).toList(); groups.sort((a, b) { final ai = orderMap[a.categoryKey] ?? 999; final bi = orderMap[b.categoryKey] ?? 999; if (ai != bi) { return ai.compareTo(bi); } return a.title.compareTo(b.title); }); return groups; } static List _groupByPaymentCard({ required BuildContext context, required List subscriptions, required PaymentCardProvider paymentCardProvider, }) { final map = >{}; for (final sub in subscriptions) { final key = sub.paymentCardId ?? _unassignedCardKey; map.putIfAbsent(key, () => []).add(sub); } final loc = AppLocalizations.of(context); final groups = []; map.forEach((key, subs) { if (key == _unassignedCardKey) { groups.add( SubscriptionGroupData( id: key, title: loc.paymentCardUnassigned, subtitle: loc.paymentCardUnassigned, subscriptions: subs, mode: SubscriptionGroupingMode.paymentCard, isUnassignedCard: true, ), ); } else { final card = paymentCardProvider.getCardById(key); final title = card?.issuerName ?? loc.paymentCardUnassigned; final subtitle = card != null ? '****${card.last4}' : loc.paymentCardUnassigned; groups.add( SubscriptionGroupData( id: key, title: title, subtitle: subtitle, subscriptions: subs, mode: SubscriptionGroupingMode.paymentCard, paymentCard: card, ), ); } }); groups.sort((a, b) { if (a.isUnassignedCard != b.isUnassignedCard) { return a.isUnassignedCard ? 1 : -1; } final aDefault = a.paymentCard?.isDefault ?? false; final bDefault = b.paymentCard?.isDefault ?? false; if (aDefault != bDefault) { return aDefault ? -1 : 1; } return a.title.toLowerCase().compareTo(b.title.toLowerCase()); }); return groups; } }