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

part of '../../child_tasks.dart';

/// Read-only parent/child projection over a task list.
///
/// This is intentionally not a scheduler. It answers ownership questions such
/// as "which tasks belong to this parent?" while leaving task placement and
/// completion rules to other domain services.
class ChildTaskView {
  /// Creates a `ChildTaskView` 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.
  ChildTaskView({
    required List<Task> tasks,
  }) : tasks = List<Task>.unmodifiable(tasks);

  /// Source task list supplied by the caller.
  final List<Task> tasks;

  /// Direct children owned by [parent], preserving source-list order.
  List<Task> childrenOf(Task parent) {
    return List<Task>.unmodifiable(
      tasks.where((task) => task.parentTaskId == parent.id),
    );
  }

  /// Direct children sorted by explicit priority while preserving row order ties.
  ///
  /// Children without priority sort after explicit priorities. Within each
  /// priority group, including the no-priority group, source-list order is kept.
  List<Task> childrenOfSortedByPriority(Task parent) {
    final indexedChildren = childrenOf(parent)
        .asMap()
        .entries
        .map(
          (entry) => _IndexedChild(
            task: entry.value,
            originalIndex: entry.key,
          ),
        )
        .toList(growable: false);

    indexedChildren.sort((a, b) {
      final priorityComparison = _priorityRank(b.task.priority)
          .compareTo(_priorityRank(a.task.priority));
      if (priorityComparison != 0) {
        return priorityComparison;
      }

      return a.originalIndex.compareTo(b.originalIndex);
    });

    return List<Task>.unmodifiable(
      indexedChildren.map((child) => child.task),
    );
  }

  /// Parent task for [child], or null when the parent is not in [tasks].
  Task? parentOf(Task child) {
    final parentId = child.parentTaskId;
    if (parentId == null) {
      return null;
    }

    for (final task in tasks) {
      if (task.id == parentId) {
        return task;
      }
    }

    return null;
  }

  /// Whether [child] is directly owned by [parent].
  bool isChildOf({
    required Task child,
    required Task parent,
  }) {
    return child.parentTaskId == parent.id;
  }

  /// Aggregate direct child status counts for [parent].
  ChildTaskSummary summaryFor(Task parent) {
    return ChildTaskSummary.fromChildren(childrenOf(parent));
  }

  /// Whether this helper would auto-complete [parent].
  bool parentShouldAutoComplete(Task parent) {
    return summaryFor(parent).allChildrenCompleted;
  }
}
