import 'package:flutter/foundation.dart';

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<McTimetableEntry> merge(
    List<McTimetableEntry> input, {
    Duration maxGap = defaultMaxGap,
  }) {
    if (input.isEmpty) return const [];

    final sorted = [...input]
      ..sort((a, b) => a.startDateTime.compareTo(b.startDateTime));

    final merged = <McTimetableEntry>[];
    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;
    }
    // Relevant für Lehrerpläne: gleicher Lehrer/Fach/Raum, aber verschiedene
    // Klassen dürfen nicht zu einem Block verschmelzen.
    if (!listEquals(a.classNames, b.classNames)) 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,
  );
}
