import 'package:flutter/foundation.dart' show immutable;

@immutable
class ScheduleSlot {
  const ScheduleSlot({
    required this.id,
    required this.startTime,
    required this.endTime,
    this.remoteId,
  });

  factory ScheduleSlot.minFromStartTime({required DateTime start}) {
    if (start.hour > 19) start = start.copyWith(hour: 8);

    return ScheduleSlot(
      id: start.millisecondsSinceEpoch.toString(),
      startTime: start.copyWith(minute: 0, second: 0),
      endTime: start.copyWith(minute: 0, second: 0).add(
            const Duration(hours: 5),
          ),
    );
  }

  final String id;
  final DateTime startTime;
  final DateTime endTime;
  final String? remoteId;

  ScheduleSlot copyWith({
    String? id,
    DateTime? startTime,
    DateTime? endTime,
    String? remoteId,
  }) {
    return ScheduleSlot(
      id: id ?? this.id,
      startTime: startTime ?? this.startTime,
      endTime: endTime ?? this.endTime,
      remoteId: remoteId ?? this.remoteId,
    );
  }

  ScheduleSlot editTime({
    DateTime? startTime,
    DateTime? endTime,
  }) {
    ScheduleSlot? slot;
    if (endTime != null) {
      slot = copyWith(
        startTime: endTime.difference(this.startTime).inHours.abs() < 5 ||
                endTime.isBefore(this.startTime)
            ? endTime.subtract(const Duration(hours: 5))
            : this.startTime,
        endTime: endTime,
      );
      if (slot.startTime.day != slot.endTime.day) {
        final DateTime midnight = DateTime(
          endTime.year,
          endTime.month,
          endTime.day,
          0,
          0,
        );

        slot = copyWith(
          startTime: midnight,
          endTime: midnight.add(const Duration(hours: 5)),
        );
      }
      return slot;
    } else if (startTime == null) {
      slot = this;
    } else {
      slot = copyWith(
        startTime: startTime,
        endTime: startTime.difference(this.endTime).inHours.abs() < 5 ||
                startTime.isAfter(this.endTime)
            ? startTime.add(const Duration(hours: 5))
            : this.endTime,
      );

      if (slot.startTime.day != slot.endTime.day) {
        final DateTime midnight = DateTime(
          startTime.year,
          startTime.month,
          startTime.day + 1,
          0,
          0,
        );

        slot = copyWith(
          startTime: midnight.subtract(const Duration(hours: 5)),
          endTime: midnight,
        );
      }
    }
    return slot;
  }

  bool isNotOverlappingWith(ScheduleSlot other) {
    // End and start time should be before other slot's start time
    if (((endTime.isBefore(other.startTime) ||
            endTime.isAtSameMomentAs(other.startTime)) &&
        startTime.isBefore(other.startTime))) {
      return true;
    }

    // Or start and end time should be after other slot's end time
    return ((startTime.isAfter(other.endTime) ||
            startTime.isAtSameMomentAs(other.endTime)) &&
        endTime.isAfter(other.endTime));
  }

  @override
  String toString() {
    return 'Slot data: ID $id\n'
        'Start time: $startTime\n'
        'End time: $endTime';
  }
}
