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

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

/// Canonical lifecycle transition service.
class TaskTransitionService {
  /// Creates a `TaskTransitionService` 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 TaskTransitionService({
    this.clock = const SystemClock(),
    this.accountingService = const TaskActivityAccountingService(),
  });

  /// Clock boundary used when no explicit occurrence time is supplied.
  final Clock clock;

  /// Activity-derived statistics updater.
  final TaskActivityAccountingService accountingService;

  /// Apply one transition to [task].
  ///
  /// [operationId] is the idempotency key. If an existing activity for the same
  /// operation and task is supplied, the command is treated as an exact duplicate
  /// and no additional changes are returned.
  TaskTransitionResult apply({
    required Task task,
    required TaskTransitionCode transitionCode,
    required String operationId,
    required String activityId,
    DateTime? occurredAt,
    DateTime? actualStart,
    DateTime? actualEnd,
    Iterable<TaskActivity> existingActivities = const <TaskActivity>[],
    Iterable<String> appliedActivityIds = const <String>[],
    List<TimeInterval> lockedIntervals = const <TimeInterval>[],
    Map<String, Object?> metadata = const <String, Object?>{},
  }) {
    final now = occurredAt ?? clock.now();
    logger.debug(() => 'Applying task transition. '
        'taskId=${task.id} transition=${transitionCode.name} '
        'operationId=$operationId taskStatus=${task.status.name} '
        'occurredAt=${now.toIso8601String()}');
    final duplicate = _duplicateActivity(
      existingActivities: existingActivities,
      taskId: task.id,
      operationId: operationId,
    );
    if (duplicate != null) {
      logger.warn(() => 'Duplicate task transition ignored. '
          'taskId=${task.id} transition=${transitionCode.name} '
          'operationId=$operationId duplicateActivityId=${duplicate.id}');
      return TaskTransitionResult(
        transitionCode: transitionCode,
        outcomeCode: TaskTransitionOutcomeCode.duplicateOperation,
        task: task,
        duplicateOfActivityId: duplicate.id,
      );
    }

    if (!_actualIntervalShapeIsValid(actualStart, actualEnd)) {
      logger.warn(() => 'Task transition rejected: invalid actual interval. '
          'taskId=${task.id} transition=${transitionCode.name} '
          'actualStart=${actualStart?.toIso8601String()} '
          'actualEnd=${actualEnd?.toIso8601String()}');
      return TaskTransitionResult(
        transitionCode: transitionCode,
        outcomeCode: TaskTransitionOutcomeCode.invalidState,
        task: task,
      );
    }

    if (_isNoOpTerminalRepeat(task, transitionCode)) {
      logger.fine(() => 'Possible issue: terminal task transition repeated. '
          'taskId=${task.id} transition=${transitionCode.name} '
          'taskStatus=${task.status.name}');
      return TaskTransitionResult(
        transitionCode: transitionCode,
        outcomeCode: TaskTransitionOutcomeCode.noOp,
        task: task,
      );
    }

    if (_isBlockedByTerminalState(task, transitionCode)) {
      logger.warn(
          () => 'Task transition rejected: terminal state blocks transition. '
              'taskId=${task.id} transition=${transitionCode.name} '
              'taskStatus=${task.status.name}');
      return TaskTransitionResult(
        transitionCode: transitionCode,
        outcomeCode: TaskTransitionOutcomeCode.invalidState,
        task: task,
      );
    }

    final result = switch (transitionCode) {
      TaskTransitionCode.complete => _complete(
          task: task,
          operationId: operationId,
          activityId: activityId,
          occurredAt: now,
          actualStart: actualStart,
          actualEnd: actualEnd,
          appliedActivityIds: appliedActivityIds,
          lockedIntervals: lockedIntervals,
          metadata: metadata,
        ),
      TaskTransitionCode.miss => _miss(
          task: task,
          operationId: operationId,
          activityId: activityId,
          occurredAt: now,
          appliedActivityIds: appliedActivityIds,
          metadata: metadata,
        ),
      TaskTransitionCode.cancel => _cancel(
          task: task,
          operationId: operationId,
          activityId: activityId,
          occurredAt: now,
          appliedActivityIds: appliedActivityIds,
          metadata: metadata,
        ),
      TaskTransitionCode.noLongerRelevant => _noLongerRelevant(
          task: task,
          operationId: operationId,
          activityId: activityId,
          occurredAt: now,
          appliedActivityIds: appliedActivityIds,
          metadata: metadata,
        ),
      TaskTransitionCode.manualPush => _movementOnly(
          task: task,
          transitionCode: transitionCode,
          activityCode: TaskActivityCode.manuallyPushed,
          operationId: operationId,
          activityId: activityId,
          occurredAt: now,
          metadata: metadata,
          appliedActivityIds: appliedActivityIds,
        ),
      TaskTransitionCode.automaticPush => _movementOnly(
          task: task,
          transitionCode: transitionCode,
          activityCode: TaskActivityCode.automaticallyPushed,
          operationId: operationId,
          activityId: activityId,
          occurredAt: now,
          metadata: metadata,
          appliedActivityIds: appliedActivityIds,
        ),
      TaskTransitionCode.moveToBacklog => _moveToBacklog(
          task: task,
          operationId: operationId,
          activityId: activityId,
          occurredAt: now,
          appliedActivityIds: appliedActivityIds,
          metadata: metadata,
        ),
      TaskTransitionCode.restoreFromBacklog => _restoreFromBacklog(
          task: task,
          operationId: operationId,
          activityId: activityId,
          occurredAt: now,
          appliedActivityIds: appliedActivityIds,
          metadata: metadata,
        ),
      TaskTransitionCode.activate => _activate(
          task: task,
          operationId: operationId,
          activityId: activityId,
          occurredAt: now,
          appliedActivityIds: appliedActivityIds,
          metadata: metadata,
        ),
    };
    logger.debug(() => 'Task transition finished. taskId=${task.id} '
        'transition=${transitionCode.name} outcome=${result.outcomeCode.name} '
        'nextStatus=${result.task.status.name} activityCount=${result.activities.length}');
    if (result.outcomeCode == TaskTransitionOutcomeCode.invalidState) {
      logger.warn(() => 'Task transition returned invalid state. '
          'taskId=${task.id} transition=${transitionCode.name} '
          'taskType=${task.type.name} previousStatus=${task.status.name} '
          'nextStatus=${result.task.status.name}');
    }
    return result;
  }

  /// Runs the `_complete` helper used inside this library.
  /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read.
  TaskTransitionResult _complete({
    required Task task,
    required String operationId,
    required String activityId,
    required DateTime occurredAt,
    required DateTime? actualStart,
    required DateTime? actualEnd,
    required Iterable<String> appliedActivityIds,
    required List<TimeInterval> lockedIntervals,
    required Map<String, Object?> metadata,
  }) {
    if (task.status != TaskStatus.planned && task.status != TaskStatus.active) {
      return _invalid(task, TaskTransitionCode.complete);
    }

    final completed = task.copyWith(
      status: TaskStatus.completed,
      updatedAt: occurredAt,
      completedAt: occurredAt,
      actualStart: actualStart,
      actualEnd: actualEnd,
      clearBacklogEntry: true,
    );
    final activities = [
      _activity(
        id: activityId,
        operationId: operationId,
        code: TaskActivityCode.completed,
        task: task,
        occurredAt: occurredAt,
        metadata: {
          ...metadata,
          'completedAt': occurredAt,
          'scheduledEnd': task.scheduledEnd,
          'actualStart': completed.actualStart,
          'actualEnd': completed.actualEnd,
          'durationMinutes': _knownDurationMinutes(
            completed,
            completed.actualStart,
            completed.actualEnd,
          ),
          'reward': task.reward.name,
          'difficulty': task.difficulty.name,
          if (task.reminderOverride != null)
            'reminderProfile': task.reminderOverride!.name,
          'pushesBeforeCompletion': _pushesBeforeCompletion(task),
        },
        nextStatus: completed.status,
      ),
    ];
    final accounted = accountingService.apply(
      task: completed,
      activities: activities,
      alreadyAppliedActivityIds: appliedActivityIds,
      lockedIntervals: lockedIntervals,
    );

    return _applied(
      transitionCode: TaskTransitionCode.complete,
      task: accounted.task,
      activities: activities,
    );
  }

  /// Runs the `_miss` helper used inside this library.
  /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read.
  TaskTransitionResult _miss({
    required Task task,
    required String operationId,
    required String activityId,
    required DateTime occurredAt,
    required Iterable<String> appliedActivityIds,
    required Map<String, Object?> metadata,
  }) {
    if (task.status != TaskStatus.planned && task.status != TaskStatus.active) {
      return _invalid(task, TaskTransitionCode.miss);
    }
    if (!task.isFlexible && !task.isRequiredVisible) {
      return _invalid(task, TaskTransitionCode.miss);
    }

    final updatedTask = task.type == TaskType.critical
        ? task.copyWith(
            status: TaskStatus.backlog,
            updatedAt: occurredAt,
            clearSchedule: true,
            backlogEnteredAt: occurredAt,
            backlogEnteredAtProvenance:
                Task.backlogEnteredAtProvenanceMovedToBacklog,
          )
        : task.copyWith(
            status: TaskStatus.missed,
            updatedAt: occurredAt,
          );
    final activities = <TaskActivity>[
      _activity(
        id: activityId,
        operationId: operationId,
        code: TaskActivityCode.missed,
        task: task,
        occurredAt: occurredAt,
        metadata: metadata,
        nextStatus: updatedTask.status,
      ),
    ];

    if (task.type == TaskType.critical) {
      activities.add(
        _activity(
          id: '$activityId:movedToBacklog',
          operationId: operationId,
          code: TaskActivityCode.movedToBacklog,
          task: task,
          occurredAt: occurredAt,
          metadata: {
            ...metadata,
            'reason': 'criticalMissed',
          },
          nextStatus: updatedTask.status,
        ),
      );
    }

    final accounted = accountingService.apply(
      task: updatedTask,
      activities: activities,
      alreadyAppliedActivityIds: appliedActivityIds,
    );

    return _applied(
      transitionCode: TaskTransitionCode.miss,
      task: accounted.task,
      activities: activities,
    );
  }

  /// Runs the `_cancel` helper used inside this library.
  /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read.
  TaskTransitionResult _cancel({
    required Task task,
    required String operationId,
    required String activityId,
    required DateTime occurredAt,
    required Iterable<String> appliedActivityIds,
    required Map<String, Object?> metadata,
  }) {
    if (task.status == TaskStatus.cancelled) {
      return _noOp(task, TaskTransitionCode.cancel);
    }
    if (!_canRemoveFromActivePlan(task)) {
      return _invalid(task, TaskTransitionCode.cancel);
    }

    final cancelled = task.copyWith(
      status: TaskStatus.cancelled,
      updatedAt: occurredAt,
      clearSchedule: true,
      clearBacklogEntry: true,
    );
    final activities = [
      _activity(
        id: activityId,
        operationId: operationId,
        code: TaskActivityCode.cancelled,
        task: task,
        occurredAt: occurredAt,
        metadata: metadata,
        nextStatus: cancelled.status,
      ),
    ];
    final accounted = accountingService.apply(
      task: cancelled,
      activities: activities,
      alreadyAppliedActivityIds: appliedActivityIds,
    );

    return _applied(
      transitionCode: TaskTransitionCode.cancel,
      task: accounted.task,
      activities: activities,
    );
  }

  /// Runs the `_noLongerRelevant` helper used inside this library.
  /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read.
  TaskTransitionResult _noLongerRelevant({
    required Task task,
    required String operationId,
    required String activityId,
    required DateTime occurredAt,
    required Iterable<String> appliedActivityIds,
    required Map<String, Object?> metadata,
  }) {
    if (task.status == TaskStatus.noLongerRelevant) {
      return _noOp(task, TaskTransitionCode.noLongerRelevant);
    }
    if (!_canRemoveFromActivePlan(task)) {
      return _invalid(task, TaskTransitionCode.noLongerRelevant);
    }

    final dismissed = task.copyWith(
      status: TaskStatus.noLongerRelevant,
      updatedAt: occurredAt,
      clearSchedule: true,
      clearBacklogEntry: true,
    );

    final activities = [
      _activity(
        id: activityId,
        operationId: operationId,
        code: TaskActivityCode.noLongerRelevant,
        task: task,
        occurredAt: occurredAt,
        metadata: metadata,
        nextStatus: dismissed.status,
      ),
    ];
    final accounted = accountingService.apply(
      task: dismissed,
      activities: activities,
      alreadyAppliedActivityIds: appliedActivityIds,
    );

    return _applied(
      transitionCode: TaskTransitionCode.noLongerRelevant,
      task: accounted.task,
      activities: activities,
    );
  }

  /// Runs the `_movementOnly` helper used inside this library.
  /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read.
  TaskTransitionResult _movementOnly({
    required Task task,
    required TaskTransitionCode transitionCode,
    required TaskActivityCode activityCode,
    required String operationId,
    required String activityId,
    required DateTime occurredAt,
    required Map<String, Object?> metadata,
    required Iterable<String> appliedActivityIds,
  }) {
    if (!task.isFlexible || task.status != TaskStatus.planned) {
      return _invalid(task, transitionCode);
    }

    final updated = task.copyWith(updatedAt: occurredAt);
    final activities = [
      _activity(
        id: activityId,
        operationId: operationId,
        code: activityCode,
        task: task,
        occurredAt: occurredAt,
        metadata: metadata,
        nextStatus: updated.status,
      ),
    ];
    final accounted = accountingService.apply(
      task: updated,
      activities: activities,
      alreadyAppliedActivityIds: appliedActivityIds,
    );

    return _applied(
      transitionCode: transitionCode,
      task: accounted.task,
      activities: activities,
    );
  }

  /// Runs the `_moveToBacklog` helper used inside this library.
  /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read.
  TaskTransitionResult _moveToBacklog({
    required Task task,
    required String operationId,
    required String activityId,
    required DateTime occurredAt,
    required Iterable<String> appliedActivityIds,
    required Map<String, Object?> metadata,
  }) {
    final canMove = (task.isFlexible || task.type == TaskType.critical) &&
        !_isTerminal(task.status);
    if (!canMove) {
      return _invalid(task, TaskTransitionCode.moveToBacklog);
    }

    final moved = task.copyWith(
      status: TaskStatus.backlog,
      updatedAt: occurredAt,
      clearSchedule: true,
      backlogEnteredAt: occurredAt,
      backlogEnteredAtProvenance: Task.backlogEnteredAtProvenanceMovedToBacklog,
    );
    final activities = [
      _activity(
        id: activityId,
        operationId: operationId,
        code: TaskActivityCode.movedToBacklog,
        task: task,
        occurredAt: occurredAt,
        metadata: metadata,
        nextStatus: moved.status,
      ),
    ];
    final accounted = accountingService.apply(
      task: moved,
      activities: activities,
      alreadyAppliedActivityIds: appliedActivityIds,
    );

    return _applied(
      transitionCode: TaskTransitionCode.moveToBacklog,
      task: accounted.task,
      activities: activities,
    );
  }

  /// Runs the `_restoreFromBacklog` helper used inside this library.
  /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read.
  TaskTransitionResult _restoreFromBacklog({
    required Task task,
    required String operationId,
    required String activityId,
    required DateTime occurredAt,
    required Iterable<String> appliedActivityIds,
    required Map<String, Object?> metadata,
  }) {
    if (task.status != TaskStatus.backlog ||
        (!task.isFlexible && task.type != TaskType.critical)) {
      return _invalid(task, TaskTransitionCode.restoreFromBacklog);
    }

    final restored = task.copyWith(
      status: TaskStatus.planned,
      updatedAt: occurredAt,
      clearBacklogEntry: true,
    );
    final activities = [
      _activity(
        id: activityId,
        operationId: operationId,
        code: TaskActivityCode.restoredFromBacklog,
        task: task,
        occurredAt: occurredAt,
        metadata: metadata,
        nextStatus: restored.status,
      ),
    ];
    final accounted = accountingService.apply(
      task: restored,
      activities: activities,
      alreadyAppliedActivityIds: appliedActivityIds,
    );

    return _applied(
      transitionCode: TaskTransitionCode.restoreFromBacklog,
      task: accounted.task,
      activities: activities,
    );
  }

  /// Runs the `_activate` helper used inside this library.
  /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read.
  TaskTransitionResult _activate({
    required Task task,
    required String operationId,
    required String activityId,
    required DateTime occurredAt,
    required Iterable<String> appliedActivityIds,
    required Map<String, Object?> metadata,
  }) {
    if (task.status != TaskStatus.planned ||
        task.isLocked ||
        task.type == TaskType.freeSlot ||
        task.type == TaskType.surprise) {
      return _invalid(task, TaskTransitionCode.activate);
    }

    final activated = task.copyWith(
      status: TaskStatus.active,
      updatedAt: occurredAt,
    );

    final activities = [
      _activity(
        id: activityId,
        operationId: operationId,
        code: TaskActivityCode.activated,
        task: task,
        occurredAt: occurredAt,
        metadata: metadata,
        nextStatus: activated.status,
      ),
    ];
    final accounted = accountingService.apply(
      task: activated,
      activities: activities,
      alreadyAppliedActivityIds: appliedActivityIds,
    );

    return _applied(
      transitionCode: TaskTransitionCode.activate,
      task: accounted.task,
      activities: activities,
    );
  }
}

/// Top-level helper that performs the `_applyActivityStats` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
TaskStatistics _applyActivityStats({
  required Task task,
  required TaskActivity activity,
  required List<TimeInterval> lockedIntervals,
}) {
  return switch (activity.code) {
    TaskActivityCode.manuallyPushed => task.stats.incrementManualPush(),
    TaskActivityCode.automaticallyPushed => task.stats.incrementAutoPush(),
    TaskActivityCode.movedToBacklog => task.stats.incrementMovedToBacklog(),
    TaskActivityCode.restoredFromBacklog =>
      task.stats.incrementRestoredFromBacklog(),
    TaskActivityCode.missed => task.stats.incrementMissed(),
    TaskActivityCode.cancelled => task.stats.incrementCancelled(),
    TaskActivityCode.completed => _applyCompletionStats(
        task: task,
        activity: activity,
        lockedIntervals: lockedIntervals,
      ),
    TaskActivityCode.noLongerRelevant ||
    TaskActivityCode.activated =>
      task.stats,
  };
}

/// Top-level helper that performs the `_applyCompletionStats` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
TaskStatistics _applyCompletionStats({
  required Task task,
  required TaskActivity activity,
  required List<TimeInterval> lockedIntervals,
}) {
  var stats = task.stats;
  final scheduledEnd = task.scheduledEnd;
  final completedAt = task.completedAt ?? activity.occurredAt;

  if (scheduledEnd != null && completedAt.isAfter(scheduledEnd)) {
    stats = stats.incrementCompletedLate();
  }

  final lockedMinutes = _actualLockedOverlapMinutes(
    task: task,
    lockedIntervals: lockedIntervals,
  );
  if (lockedMinutes > 0) {
    stats = stats.incrementCompletedDuringLockedHours(lockedMinutes);
  }

  final pushesBeforeCompletion =
      _intMetadata(activity.metadata['pushesBeforeCompletion']) ??
          _pushesBeforeCompletion(task);

  return stats.recordPushesBeforeCompletion(pushesBeforeCompletion);
}

/// Top-level helper that performs the `_actualLockedOverlapMinutes` 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 _actualLockedOverlapMinutes({
  required Task task,
  required List<TimeInterval> lockedIntervals,
}) {
  final actualStart = task.actualStart;
  final actualEnd = task.actualEnd;
  if (actualStart == null ||
      actualEnd == null ||
      !actualStart.isBefore(actualEnd) ||
      lockedIntervals.isEmpty) {
    return 0;
  }

  final actualInterval = TimeInterval(start: actualStart, end: actualEnd);
  final intersections = <TimeInterval>[];

  for (final lockedInterval in lockedIntervals) {
    if (!actualInterval.overlaps(lockedInterval)) {
      continue;
    }
    intersections.add(
      TimeInterval(
        start: _latest(actualInterval.start, lockedInterval.start),
        end: _earliest(actualInterval.end, lockedInterval.end),
      ),
    );
  }

  if (intersections.isEmpty) {
    return 0;
  }

  intersections.sort((left, right) => left.start.compareTo(right.start));
  var total = Duration.zero;
  var current = intersections.first;
  for (final interval in intersections.skip(1)) {
    if (interval.start.isAfter(current.end)) {
      total += current.duration;
      current = interval;
      continue;
    }

    current = TimeInterval(
      start: current.start,
      end: _latest(current.end, interval.end),
    );
  }
  total += current.duration;

  return total.inMinutes;
}

/// Top-level helper that performs the `_pushesBeforeCompletion` 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 _pushesBeforeCompletion(Task task) {
  return task.stats.manuallyPushedCount + task.stats.autoPushedCount;
}

/// Top-level helper that performs the `_knownDurationMinutes` 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? _knownDurationMinutes(
  Task task,
  DateTime? actualStart,
  DateTime? actualEnd,
) {
  if (actualStart != null &&
      actualEnd != null &&
      actualStart.isBefore(actualEnd)) {
    final actualMinutes = actualEnd.difference(actualStart).inMinutes;
    if (actualMinutes > 0) {
      return actualMinutes;
    }
  }

  return task.durationMinutes;
}

/// Top-level helper that performs the `_intMetadata` 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? _intMetadata(Object? value) {
  return value is int ? value : null;
}

/// Top-level helper that performs the `_earliest` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
DateTime _earliest(DateTime first, DateTime second) {
  return first.isBefore(second) ? first : second;
}

/// Top-level helper that performs the `_latest` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
DateTime _latest(DateTime first, DateTime second) {
  return first.isAfter(second) ? first : second;
}

/// Top-level helper that performs the `_applied` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
TaskTransitionResult _applied({
  required TaskTransitionCode transitionCode,
  required Task task,
  required List<TaskActivity> activities,
}) {
  return TaskTransitionResult(
    transitionCode: transitionCode,
    outcomeCode: TaskTransitionOutcomeCode.applied,
    task: task,
    activities: activities,
  );
}

/// Top-level helper that performs the `_invalid` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
TaskTransitionResult _invalid(Task task, TaskTransitionCode transitionCode) {
  return TaskTransitionResult(
    transitionCode: transitionCode,
    outcomeCode: TaskTransitionOutcomeCode.invalidState,
    task: task,
  );
}

/// Top-level helper that performs the `_noOp` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
TaskTransitionResult _noOp(Task task, TaskTransitionCode transitionCode) {
  logger.fine(() => 'Possible issue: task transition no-op. taskId=${task.id} '
      'transition=${transitionCode.name} taskStatus=${task.status.name}');
  return TaskTransitionResult(
    transitionCode: transitionCode,
    outcomeCode: TaskTransitionOutcomeCode.noOp,
    task: task,
  );
}

/// Top-level helper that performs the `_activity` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
TaskActivity _activity({
  required String id,
  required String operationId,
  required TaskActivityCode code,
  required Task task,
  required DateTime occurredAt,
  required Map<String, Object?> metadata,
  required TaskStatus nextStatus,
}) {
  return TaskActivity(
    id: id,
    operationId: operationId,
    code: code,
    taskId: task.id,
    projectId: task.projectId,
    occurredAt: occurredAt,
    metadata: {
      ...metadata,
      'previousStatus': task.status.name,
      'nextStatus': nextStatus.name,
    },
  );
}

/// Top-level helper that performs the `_duplicateActivity` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
TaskActivity? _duplicateActivity({
  required Iterable<TaskActivity> existingActivities,
  required String taskId,
  required String operationId,
}) {
  for (final activity in existingActivities) {
    if (activity.taskId == taskId && activity.operationId == operationId) {
      return activity;
    }
  }

  return null;
}

/// Top-level helper that performs the `_actualIntervalShapeIsValid` 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 _actualIntervalShapeIsValid(DateTime? actualStart, DateTime? actualEnd) {
  if (actualStart == null && actualEnd == null) {
    return true;
  }
  return actualStart != null &&
      actualEnd != null &&
      actualStart.isBefore(actualEnd);
}

/// Top-level helper that performs the `_isNoOpTerminalRepeat` 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 _isNoOpTerminalRepeat(Task task, TaskTransitionCode transitionCode) {
  return (task.status == TaskStatus.completed &&
          transitionCode == TaskTransitionCode.complete) ||
      (task.status == TaskStatus.cancelled &&
          transitionCode == TaskTransitionCode.cancel) ||
      (task.status == TaskStatus.noLongerRelevant &&
          transitionCode == TaskTransitionCode.noLongerRelevant);
}

/// Top-level helper that performs the `_isBlockedByTerminalState` 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 _isBlockedByTerminalState(Task task, TaskTransitionCode transitionCode) {
  if (!_isTerminal(task.status)) {
    return false;
  }
  return !_isNoOpTerminalRepeat(task, transitionCode);
}

/// Top-level helper that performs the `_isTerminal` 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 _isTerminal(TaskStatus status) {
  return status == TaskStatus.completed ||
      status == TaskStatus.cancelled ||
      status == TaskStatus.noLongerRelevant;
}

/// Top-level helper that performs the `_canRemoveFromActivePlan` 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 _canRemoveFromActivePlan(Task task) {
  return task.status == TaskStatus.planned ||
      task.status == TaskStatus.active ||
      task.status == TaskStatus.backlog ||
      task.status == TaskStatus.missed;
}

/// Top-level helper that performs the `_requiredTrimmed` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
String _requiredTrimmed(String value, String name) {
  final trimmed = value.trim();
  if (trimmed.isEmpty) {
    throw ArgumentError.value(value, name, 'Value is required.');
  }
  return trimmed;
}
