// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only

part of '../../repositories.dart';

/// In-memory snapshot repository useful for tests and early application wiring.
class InMemorySchedulingSnapshotRepository
    implements SchedulingSnapshotRepository {
  /// Creates a `InMemorySchedulingSnapshotRepository` instance with the values required by its invariants.
  /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
  InMemorySchedulingSnapshotRepository([
    Iterable<SchedulingStateSnapshot> initialSnapshots = const [],
  ]) : _snapshotsById = {
          for (final snapshot in initialSnapshots) snapshot.id: snapshot,
        };

  /// Private state stored as `_snapshotsById` for this implementation.
  /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior.
  final Map<String, SchedulingStateSnapshot> _snapshotsById;

  /// Runs the `findById` operation and completes after its asynchronous work finishes.
  /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order.
  @override
  Future<SchedulingStateSnapshot?> findById(String id) async {
    return _snapshotsById[id];
  }

  /// Runs the `findInWindow` operation and completes after its asynchronous work finishes.
  /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order.
  @override
  Future<List<SchedulingStateSnapshot>> findInWindow(
    SchedulingWindow window,
  ) async {
    return List<SchedulingStateSnapshot>.unmodifiable(
      _snapshotsById.values.where(
        (snapshot) => snapshot.window.interval.overlaps(window.interval),
      ),
    );
  }

  /// Runs the `save` operation and completes after its asynchronous work finishes.
  /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order.
  @override
  Future<void> save(SchedulingStateSnapshot snapshot) async {
    _snapshotsById[snapshot.id] = snapshot;
  }
}

/// Top-level helper that performs the `_page<T>` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
RepositoryPage<T> _page<T>(List<T> sortedItems, RepositoryPageRequest request) {
  final offset = int.tryParse(request.cursor ?? '') ?? 0;
  final safeOffset = offset.clamp(0, sortedItems.length);
  final end = (safeOffset + request.limit).clamp(0, sortedItems.length);
  final items = sortedItems.sublist(safeOffset, end);
  final nextCursor = end < sortedItems.length ? end.toString() : null;
  return RepositoryPage<T>(
    items: List<T>.unmodifiable(items),
    nextCursor: nextCursor,
  );
}

/// Top-level helper that performs the `_taskOverlapsWindow` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
bool _taskOverlapsWindow(Task task, SchedulingWindow window) {
  final start = task.scheduledStart;
  final end = task.scheduledEnd;
  if (start == null || end == null) {
    return false;
  }
  return TimeInterval(start: start, end: end).overlaps(window.interval);
}

/// Top-level helper that performs the `_compareTaskIds` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
int _compareTaskIds(Task left, Task right) => left.id.compareTo(right.id);

/// Top-level helper that performs the `_compareScheduledTasks` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
int _compareScheduledTasks(Task left, Task right) {
  final leftStart = left.scheduledStart;
  final rightStart = right.scheduledStart;
  if (leftStart != null && rightStart != null) {
    final startComparison = leftStart.compareTo(rightStart);
    if (startComparison != 0) {
      return startComparison;
    }
  }
  return left.id.compareTo(right.id);
}

/// Top-level helper that performs the `_compareBacklogCandidates` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
int _compareBacklogCandidates(Task left, Task right) {
  final createdComparison = left.createdAt.compareTo(right.createdAt);
  if (createdComparison != 0) {
    return createdComparison;
  }
  return left.id.compareTo(right.id);
}

/// Top-level helper that performs the `_compareProjects` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
int _compareProjects(ProjectProfile left, ProjectProfile right) {
  final nameComparison = left.name.compareTo(right.name);
  if (nameComparison != 0) {
    return nameComparison;
  }
  return left.id.compareTo(right.id);
}

/// Top-level helper that performs the `_compareLockedBlocks` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
int _compareLockedBlocks(LockedBlock left, LockedBlock right) {
  final nameComparison = left.name.compareTo(right.name);
  if (nameComparison != 0) {
    return nameComparison;
  }
  return left.id.compareTo(right.id);
}

/// Top-level helper that performs the `_compareLockedOverrides` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
int _compareLockedOverrides(
  LockedBlockOverride left,
  LockedBlockOverride right,
) {
  final dateComparison = left.date.compareTo(right.date);
  if (dateComparison != 0) {
    return dateComparison;
  }
  final createdComparison = left.createdAt.compareTo(right.createdAt);
  if (createdComparison != 0) {
    return createdComparison;
  }
  return left.id.compareTo(right.id);
}
