import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:hive_flutter/hive_flutter.dart'; import '../models/sake_item.dart'; // SakeItem exports ItemType import '../providers/theme_provider.dart'; import '../constants/app_constants.dart'; /// Badge unlock result class BadgeUnlock { final String id; final String name; final String icon; BadgeUnlock(this.id, this.name, this.icon); } /// Gamification Service: Badge unlock logic class GamificationService { /// Check badge conditions and unlock new badges /// Returns: List of newly unlocked badges static Future> checkAndUnlockBadges(WidgetRef ref) async { final userProfile = ref.read(userProfileProvider); final unlockedBadges = userProfile.unlockedBadges.toSet(); final newlyUnlocked = []; // Get all SakeItems from Hive final box = Hive.box('sake_items'); final allRawItems = box.values.toList(); // Phase D5: Exclude set products from badge calculations (sets contain multiple items) final allItems = allRawItems.where((item) => item.itemType == ItemType.sake).toList(); // 1. Badge: 初めての一歩 (first_step) // Condition: Register at least 1 sake if (!unlockedBadges.contains('first_step') && allItems.isNotEmpty) { newlyUnlocked.add(BadgeUnlock('first_step', '初めての一歩', '🍶')); } // 2. Badge: 東北制覇 (regional_tohoku) // Condition: Register sake from all 6 Tohoku prefectures if (!unlockedBadges.contains('regional_tohoku')) { final tohokuPrefectures = {'青森県', '岩手県', '宮城県', '秋田県', '山形県', '福島県'}; final registeredPrefectures = allItems .map((item) => item.displayData.displayPrefecture) .where((pref) => tohokuPrefectures.contains(pref)) .toSet(); if (registeredPrefectures.length == 6) { newlyUnlocked.add(BadgeUnlock('regional_tohoku', '東北制覇', '👹')); } } // 3. Badge: 辛口党 (flavor_dry) // Condition: Register 10+ sake with SMV >= +5 if (!unlockedBadges.contains('flavor_dry')) { final dryItems = allItems.where((item) { final smv = item.hiddenSpecs.sakeMeterValue; return smv != null && smv >= AppConstants.dryTypeSakeMeterThreshold; }).toList(); if (dryItems.length >= 10) { newlyUnlocked.add(BadgeUnlock('flavor_dry', '辛口党', '🌶️')); } } // 4. Badge: 関東制覇 (regional_kanto) // Condition: Register sake from all 7 Kanto prefectures if (!unlockedBadges.contains('regional_kanto')) { final kantoPrefectures = {'茨城県', '栃木県', '群馬県', '埼玉県', '千葉県', '東京都', '神奈川県'}; final registeredPrefectures = allItems .map((item) => item.displayData.displayPrefecture) .where((pref) => kantoPrefectures.contains(pref)) .toSet(); if (registeredPrefectures.length == 7) { newlyUnlocked.add(BadgeUnlock('regional_kanto', '関東制覇', '🗻')); } } // 5. Badge: 関西制覇 (regional_kansai) // Condition: Register sake from all 6 Kansai prefectures if (!unlockedBadges.contains('regional_kansai')) { final kansaiPrefectures = {'滋賀県', '京都府', '大阪府', '兵庫県', '奈良県', '和歌山県'}; final registeredPrefectures = allItems .map((item) => item.displayData.displayPrefecture) .where((pref) => kansaiPrefectures.contains(pref)) .toSet(); if (registeredPrefectures.length == 6) { newlyUnlocked.add(BadgeUnlock('regional_kansai', '関西制覇', '🏯')); } } // 6. Badge: 愛好家 (collector_10) // Condition: Register 10+ sake if (!unlockedBadges.contains('collector_10') && allItems.length >= 10) { newlyUnlocked.add(BadgeUnlock('collector_10', '愛好家', '🎉')); } // 7. Badge: コレクター (collector_50) // Condition: Register 50+ sake if (!unlockedBadges.contains('collector_50') && allItems.length >= AppConstants.collectorBadgeThreshold) { newlyUnlocked.add(BadgeUnlock('collector_50', 'コレクター', '📚')); } // 8. Badge: レジェンド (collector_100) // Condition: Register 100+ sake if (!unlockedBadges.contains('collector_100') && allItems.length >= 100) { newlyUnlocked.add(BadgeUnlock('collector_100', 'レジェンド', '👑')); } // 9. Badge: 甘口党 (flavor_sweet) // Condition: Register 10+ sake with SMV <= -3 if (!unlockedBadges.contains('flavor_sweet')) { final sweetItems = allItems.where((item) { final smv = item.hiddenSpecs.sakeMeterValue; return smv != null && smv <= -3.0; }).toList(); if (sweetItems.length >= 10) { newlyUnlocked.add(BadgeUnlock('flavor_sweet', '甘口党', '🍯')); } } // 10. Badge: 香りの貴族 (flavor_aromatic) // Condition: Register 10+ sake with high aroma score (>= 4.0) if (!unlockedBadges.contains('flavor_aromatic')) { final aromaticItems = allItems.where((item) { final tasteStats = item.hiddenSpecs.sakeTasteStats; return tasteStats.aroma >= 4.0; }).toList(); if (aromaticItems.length >= 10) { newlyUnlocked.add(BadgeUnlock('flavor_aromatic', '香りの貴族', '🌸')); } } // Update UserProfile if there are newly unlocked badges if (newlyUnlocked.isNotEmpty) { final updatedBadges = [...unlockedBadges, ...newlyUnlocked.map((b) => b.id)]; await ref.read(userProfileProvider.notifier).updateUnlockedBadges(updatedBadges); } return newlyUnlocked; } }