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

part of '../../project_statistics.dart';

/// Updates project statistics from canonical task activities exactly once.
class ProjectStatisticsAggregationService {
  /// Creates a `ProjectStatisticsAggregationService` 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 ProjectStatisticsAggregationService();

  /// Apply completion [activities] to [statistics].
  ///
  /// [alreadyAppliedActivityIds] is supplied by the application/persistence
  /// boundary. This service returns the new ids so Block 14 can persist task,
  /// activity, and aggregate mutations atomically.
  ProjectStatisticsApplicationResult apply({
    required ProjectStatistics statistics,
    required Iterable<TaskActivity> activities,
    Iterable<Task> tasks = const <Task>[],
    Iterable<String> alreadyAppliedActivityIds = const <String>[],
  }) {
    final taskById = {
      for (final task in tasks) task.id: task,
    };
    final appliedIds = alreadyAppliedActivityIds.toSet();
    final newlyAppliedIds = <String>[];
    var current = statistics;

    for (final activity in activities) {
      if (activity.projectId != statistics.projectId ||
          activity.code != TaskActivityCode.completed ||
          appliedIds.contains(activity.id)) {
        continue;
      }

      final task = taskById[activity.taskId];
      final completedAt = _dateTimeMetadata(activity.metadata['completedAt']) ??
          activity.occurredAt;
      final pushesBeforeCompletion =
          _intMetadata(activity.metadata['pushesBeforeCompletion']) ??
              _pushesBeforeCompletion(task);

      current = current.recordCompletion(
        completedAt: completedAt,
        durationMinutes: _durationMinutes(activity, task),
        pushesBeforeCompletion: pushesBeforeCompletion,
        reward: _rewardLevel(activity.metadata['reward']) ?? task?.reward,
        difficulty: _difficultyLevel(activity.metadata['difficulty']) ??
            task?.difficulty,
        reminderProfile:
            _reminderProfile(activity.metadata['reminderProfile']) ??
                task?.reminderOverride,
      );
      appliedIds.add(activity.id);
      newlyAppliedIds.add(activity.id);
    }

    return ProjectStatisticsApplicationResult(
      statistics: current,
      appliedActivityIds: newlyAppliedIds,
    );
  }
}
