import 'package:shared_preferences/shared_preferences.dart'; /// Registo local (por criança) de escovagens e da meta semanal. /// Segue o mesmo padrão de [QuizPrefs]: chaves com sufixo `_scopeId`, /// guardadas via [SharedPreferences], sem qualquer chamada ao Supabase. /// /// Cada escovagem é guardada com a hora exata (não só a data), para permitir /// até [maxPerDay] registos por dia — a criança pode escovar os dentes de /// manhã, à tarde e à noite, a qualquer hora. class BrushingPrefs { static const String _kGoalKey = 'brushing_weekly_goal'; static const String _kDatesKey = 'brushing_dates'; static const int maxPerDay = 3; static const int defaultWeeklyGoal = maxPerDay * 7; static String _key(String base, String scopeId) => '${base}_$scopeId'; static DateTime _currentWeekMonday() { final now = DateTime.now(); return DateTime( now.year, now.month, now.day, ).subtract(Duration(days: now.weekday - 1)); } /// Lê as escovagens guardadas e, de caminho, descarta (apaga do /// armazenamento) qualquer registo de semanas anteriores — o contador /// semanal deve zerar a cada nova semana, não só na exibição mas também /// nos dados guardados, para não crescer para sempre. static Future> _getEntries(String scopeId) async { final prefs = await SharedPreferences.getInstance(); final key = _key(_kDatesKey, scopeId); final raw = prefs.getStringList(key) ?? const []; final entries = raw.map(DateTime.tryParse).whereType().toList(); final monday = _currentWeekMonday(); final kept = entries .where((d) => !DateTime(d.year, d.month, d.day).isBefore(monday)) .toList(); if (kept.length != entries.length) { await prefs.setStringList( key, kept.map((d) => d.toIso8601String()).toList(), ); } return kept; } static Future getWeeklyGoal(String scopeId) async { final prefs = await SharedPreferences.getInstance(); return prefs.getInt(_key(_kGoalKey, scopeId)) ?? defaultWeeklyGoal; } static Future setWeeklyGoal(String scopeId, int goal) async { final prefs = await SharedPreferences.getInstance(); await prefs.setInt(_key(_kGoalKey, scopeId), goal); } static Future getTodayCount(String scopeId) async { final entries = await _getEntries(scopeId); final now = DateTime.now(); return entries .where( (d) => d.year == now.year && d.month == now.month && d.day == now.day, ) .length; } static Future canLogMore(String scopeId) async { return (await getTodayCount(scopeId)) < maxPerDay; } /// Regista uma escovagem agora — não faz nada se o limite diário já foi /// atingido (chamador deve verificar [canLogMore] antes, se quiser avisar /// o utilizador). static Future logToday(String scopeId) async { if (!(await canLogMore(scopeId))) return; // Usa as entradas já podadas (só da semana atual) para não ressuscitar // registos de semanas anteriores ao gravar de volta. final entries = await _getEntries(scopeId); entries.add(DateTime.now()); final prefs = await SharedPreferences.getInstance(); await prefs.setStringList( _key(_kDatesKey, scopeId), entries.map((d) => d.toIso8601String()).toList(), ); } /// Já atingiu o limite diário de [maxPerDay] escovagens hoje? static Future hasReachedDailyLimit(String scopeId) async { return (await getTodayCount(scopeId)) >= maxPerDay; } /// Conta quantas escovagens foram registadas na semana atual /// (segunda-feira a domingo). [_getEntries] já descarta semanas /// anteriores, por isso todas as entradas devolvidas já são desta semana. static Future getWeekCount(String scopeId) async { return (await _getEntries(scopeId)).length; } }