/// A recurring excuse plus the pattern the app confronts you with, e.g. /// "Too tired has appeared 14 times this month, 11 of them on gym days, /// 9 of them after 7pm. Consider moving gym to morning." class ExcuseCluster { String? id; String label; int occurrences; /// Weekday histogram (1 = Monday) — where this excuse concentrates. Map byWeekday; /// Hour-of-day histogram — when it concentrates. Map byHour; /// The category this excuse most often attaches to. String dominantCategory; /// The confrontation copy rendered to the user. String insight; ExcuseCluster({ this.id, this.label = "", this.occurrences = 0, Map? byWeekday, Map? byHour, this.dominantCategory = "", this.insight = "", }) : byWeekday = byWeekday ?? {}, byHour = byHour ?? {}; factory ExcuseCluster.fromJson(Map json) { final Map weekdays = {}; if (json['byWeekday'] != null) { (json['byWeekday'] as Map).forEach((key, value) { weekdays[int.tryParse(key) ?? 1] = value ?? 0; }); } final Map hours = {}; if (json['byHour'] != null) { (json['byHour'] as Map).forEach((key, value) { hours[int.tryParse(key) ?? 0] = value ?? 0; }); } return ExcuseCluster( id: json['id'], label: json['label'] ?? "", occurrences: json['occurrences'] ?? 0, byWeekday: weekdays, byHour: hours, dominantCategory: json['dominantCategory'] ?? "", insight: json['insight'] ?? "", ); } Map toJson() { final Map data = {}; data['id'] = id; data['label'] = label; data['occurrences'] = occurrences; data['byWeekday'] = byWeekday.map((key, value) => MapEntry(key.toString(), value)); data['byHour'] = byHour.map((key, value) => MapEntry(key.toString(), value)); data['dominantCategory'] = dominantCategory; data['insight'] = insight; return data; } }