import 'package:freezed_annotation/freezed_annotation.dart';

part 'widget_data.freezed.dart';
part 'widget_data.g.dart';

/// Status mirror of [LessonStatus] in
/// `lib/view/pages/timetable/data/lesson_status.dart`. Native widget code
/// switches on the string form, so the JSON name MUST stay stable.
enum WidgetLessonStatus {
  regular,
  ongoing,
  past,
  cancelled,
  irregular,
  teacherChanged,
  event,
  // Sonder-Lesson-Types (Aufsicht, Sprechstunde, …) — Native-Widget-Renderer,
  // die den Status noch nicht kennen, fallen still auf den regulären Stil
  // zurück, sobald der String dort unbekannt ist.
  duty,
}

@freezed
abstract class WidgetLesson with _$WidgetLesson {
  const factory WidgetLesson({
    required DateTime start,
    required DateTime end,
    required String subjectShort,
    String? subjectLong,
    String? room,
    /// On teacher accounts this carries the class label ("7a") instead of the
    /// teacher short name — see `WidgetDataMapper` `showClassInsteadOfTeacher`;
    /// [originalTeacher] is null in that case.
    String? teacher,
    String? originalTeacher,
    required WidgetLessonStatus status,
    String? customColor,
    @Default(0) int siblingCount,
  }) = _WidgetLesson;

  factory WidgetLesson.fromJson(Map<String, Object?> json) =>
      _$WidgetLessonFromJson(json);
}

@freezed
abstract class WidgetPeriod with _$WidgetPeriod {
  const factory WidgetPeriod({
    /// Webuntis period name — typically the lesson number as string ("1",
    /// "2", "3", …). Native renderers append a trailing "." for display.
    required String name,
    /// Minutes since midnight, e.g. 480 for 08:00. Cheap to read in
    /// Kotlin/Swift without re-parsing time strings.
    required int startMinutes,
    required int endMinutes,
    /// Position on the **virtual** time axis used by the widget. Small
    /// between-lesson gaps are squeezed out so periods stack flush; only
    /// big breaks (> 5 min) remain as visible gaps. Computed by the
    /// mapper so native renderers don't have to redo the maths.
    required int virtualStartMinutes,
    required int virtualEndMinutes,
  }) = _WidgetPeriod;

  factory WidgetPeriod.fromJson(Map<String, Object?> json) =>
      _$WidgetPeriodFromJson(json);
}

/// Per-day metadata for the week payload, so native renderers can derive a
/// single day's view (including its holiday state) without a day payload.
@freezed
abstract class WidgetDayInfo with _$WidgetDayInfo {
  const factory WidgetDayInfo({
    required DateTime date,
    @Default(false) bool isHoliday,
    String? holidayName,
  }) = _WidgetDayInfo;

  factory WidgetDayInfo.fromJson(Map<String, Object?> json) =>
      _$WidgetDayInfoFromJson(json);
}

@freezed
abstract class WidgetTimetableData with _$WidgetTimetableData {
  const factory WidgetTimetableData({
    required DateTime fetchedAt,
    /// The day this widget snapshot is "about" — display anchor.
    /// For the day variant: the rendered school day.
    /// For the week variant: the Monday of the rendered school week.
    required DateTime anchorDate,
    required List<WidgetLesson> lessons,
    @Default(<WidgetPeriod>[]) List<WidgetPeriod> periods,
    @Default(false) bool isHoliday,
    String? holidayName,
    /// Week payload only: one entry per day of the covered window.
    @Default(<WidgetDayInfo>[]) List<WidgetDayInfo> days,
  }) = _WidgetTimetableData;

  factory WidgetTimetableData.fromJson(Map<String, Object?> json) =>
      _$WidgetTimetableDataFromJson(json);
}
