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

part of '../../task_lifecycle.dart';

/// Applies task-statistic effects from internal activities exactly once.
class TaskActivityAccountingService {
  /// Creates a `TaskActivityAccountingService` 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.
  const TaskActivityAccountingService();

  /// Apply [activities] to [task], skipping ids already present in
  /// [alreadyAppliedActivityIds].
  ///
  /// Completion accounting uses explicit completion timestamps and actual
  /// intervals. If a completion has a timestamp but no actual interval, locked
  /// minutes are left at zero rather than inferred from the planned slot.
  TaskActivityApplicationResult apply({
    required Task task,
    required Iterable<TaskActivity> activities,
    Iterable<String> alreadyAppliedActivityIds = const <String>[],
    List<TimeInterval> lockedIntervals = const <TimeInterval>[],
  }) {
    final appliedIds = alreadyAppliedActivityIds.toSet();
    final newlyAppliedIds = <String>[];
    var current = task;

    for (final activity in activities) {
      if (activity.taskId != task.id || appliedIds.contains(activity.id)) {
        continue;
      }

      final nextStats = _applyActivityStats(
        task: current,
        activity: activity,
        lockedIntervals: lockedIntervals,
      );
      current = current.copyWith(stats: nextStats);
      appliedIds.add(activity.id);
      newlyAppliedIds.add(activity.id);
    }

    return TaskActivityApplicationResult(
      task: current,
      appliedActivityIds: newlyAppliedIds,
    );
  }
}
