import '../../../../api/marianumconnect/queries/timetable_get_week/timetable_get_week_response.dart'; /// Combines back-to-back lessons with identical subject/room/teacher/status /// into a single visual block. Shared by the calendar tile builder and the /// home-widget data mapper so both surfaces show the same merged spans. /// /// Built as a new list rather than mutating inputs — earlier in-place merges /// extended merged blocks further on every rebuild when the same lesson /// objects were observed again. class LessonMerger { const LessonMerger._(); static const Duration defaultMaxGap = Duration(minutes: 5); static List merge( List input, { Duration maxGap = defaultMaxGap, }) { if (input.isEmpty) return const []; final sorted = [...input] ..sort((a, b) => a.startDateTime.compareTo(b.startDateTime)); final merged = []; for (final current in sorted) { if (merged.isNotEmpty && _canMerge(merged.last, current, maxGap)) { final prev = merged.removeLast(); merged.add(_extendedEnd(prev, current.endTime)); } else { merged.add(current); } } return merged; } static bool _canMerge( McTimetableEntry a, McTimetableEntry b, Duration maxGap, ) { if (a.subjects.firstOrNull != b.subjects.firstOrNull) return false; if (a.rooms.firstOrNull != b.rooms.firstOrNull) return false; if (a.teachers.firstOrNull?.shortName != b.teachers.firstOrNull?.shortName) { return false; } if (a.status != b.status) return false; // Lower bound on the gap — without it, two identical-metadata lessons that // overlap in time would silently collapse into one. final gap = b.startDateTime.difference(a.endDateTime); return !gap.isNegative && gap <= maxGap; } static McTimetableEntry _extendedEnd( McTimetableEntry source, DateTime newEndTime, ) => McTimetableEntry( id: source.id, date: source.date, startTime: source.startTime, endTime: newEndTime, subjects: source.subjects, teachers: source.teachers, rooms: source.rooms, classNames: source.classNames, lessonType: source.lessonType, status: source.status, substitutionText: source.substitutionText, lessonText: source.lessonText, infoText: source.infoText, ); }