import 'package:shared_preferences/shared_preferences.dart'; import 'dart:convert'; class ScoreManager { static const String _todayScoreKey = 'today_score'; static const String _totalScoreKey = 'total_score'; static const String _dailyHistoryKey = 'daily_history'; static const String _lastDateKey = 'last_date'; static int _todayScore = 0; static int _totalScore = 0; static Map _dailyHistory = {}; static int get todayScore => _todayScore; static int get totalScore => _totalScore; static Map get dailyHistory => Map.from(_dailyHistory); /// Initialize the score manager - loads saved data static Future initialize() async { await _loadScores(); await _checkNewDay(); } /// Add points to today's score static Future addScore(int points) async { _todayScore += points; _totalScore += points; await _saveScores(); } /// Reset today's score (for testing purposes) static Future resetTodayScore() async { _todayScore = 0; await _saveScores(); } /// Get scores for the last N days (for charts) static List> getLastDaysScores(int days) { final now = DateTime.now(); final result = >[]; for (int i = days - 1; i >= 0; i--) { final date = now.subtract(Duration(days: i)); final dateStr = _formatDate(date); final score = _dailyHistory[dateStr] ?? 0; result.add(MapEntry(dateStr, score)); } return result; } /// Get weekly totals for the last N weeks static List> getWeeklyScores(int weeks) { final now = DateTime.now(); final result = >[]; for (int i = weeks - 1; i >= 0; i--) { final weekStart = now.subtract(Duration(days: now.weekday - 1 + (i * 7))); int weekTotal = 0; for (int day = 0; day < 7; day++) { final date = weekStart.add(Duration(days: day)); final dateStr = _formatDate(date); weekTotal += _dailyHistory[dateStr] ?? 0; } final weekLabel = 'Week of ${_formatDate(weekStart)}'; result.add(MapEntry(weekLabel, weekTotal)); } return result; } /// Get total bubbles popped (approximate based on score) static int get totalBubblesPopped => _totalScore ~/ 10; // 10 points per bubble /// Get average daily score static double get averageDailyScore { if (_dailyHistory.isEmpty) return 0.0; final total = _dailyHistory.values.fold(0, (a, b) => a + b); return total / _dailyHistory.length; } /// Get current streak (consecutive days with score > 0) static int get currentStreak { final now = DateTime.now(); int streak = 0; for (int i = 0; i < 365; i++) { // Check up to a year final date = now.subtract(Duration(days: i)); final dateStr = _formatDate(date); final score = _dailyHistory[dateStr] ?? 0; if (score > 0) { streak++; } else { break; } } return streak; } /// Get best day score static int get bestDayScore { if (_dailyHistory.isEmpty) return _todayScore; return _dailyHistory.values.fold(_todayScore, (a, b) => a > b ? a : b); } static Future _loadScores() async { final prefs = await SharedPreferences.getInstance(); // Handle potential type mismatches from previous versions try { _todayScore = prefs.getInt(_todayScoreKey) ?? 0; } catch (e) { // Clean up corrupted data await prefs.remove(_todayScoreKey); _todayScore = 0; } try { _totalScore = prefs.getInt(_totalScoreKey) ?? 0; } catch (e) { // Clean up corrupted data await prefs.remove(_totalScoreKey); _totalScore = 0; } final historyJson = prefs.getString(_dailyHistoryKey) ?? '{}'; try { final historyMap = json.decode(historyJson) as Map; _dailyHistory = historyMap.map((key, value) => MapEntry(key, value as int)); } catch (e) { _dailyHistory = {}; // Clean up corrupted data await prefs.remove(_dailyHistoryKey); } } static Future _saveScores() async { final prefs = await SharedPreferences.getInstance(); await prefs.setInt(_todayScoreKey, _todayScore); await prefs.setInt(_totalScoreKey, _totalScore); await prefs.setString(_lastDateKey, DateTime.now().toIso8601String().split('T')[0]); // Save today's score to history final today = _formatDate(DateTime.now()); _dailyHistory[today] = _todayScore; final historyJson = json.encode(_dailyHistory); await prefs.setString(_dailyHistoryKey, historyJson); } static Future _checkNewDay() async { final prefs = await SharedPreferences.getInstance(); final lastDate = prefs.getString(_lastDateKey); final today = _formatDate(DateTime.now()); if (lastDate != today) { // New day - save yesterday's score and reset today's if (lastDate != null && _todayScore > 0) { _dailyHistory[lastDate] = _todayScore; } _todayScore = 0; await prefs.setString(_lastDateKey, today); await _saveScores(); } } static String _formatDate(DateTime date) { return '${date.year}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')}'; } /// Clean up old data (keep only last 365 days) static Future cleanupOldData() async { final cutoffDate = DateTime.now().subtract(const Duration(days: 365)); final cutoffStr = _formatDate(cutoffDate); _dailyHistory.removeWhere((date, score) => date.compareTo(cutoffStr) < 0); await _saveScores(); } }