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

/// Tests Domain Contracts behavior for the Scheduler Core package.
library;

import 'package:scheduler_core/scheduler_core.dart';
import 'package:test/test.dart';

/// Entry point for this executable Dart file.
/// It wires the local command, test, or application behavior needed by this repository without exposing additional public API.
void main() {
  group('V1 lifecycle contracts', () {
    final now = DateTime(2026, 6, 24, 9);
    const engine = SchedulingEngine();

    test('durable task statuses exclude movement and V2 burnout labels', () {
      expect(TaskStatus.values, const [
        TaskStatus.planned,
        TaskStatus.active,
        TaskStatus.completed,
        TaskStatus.missed,
        TaskStatus.cancelled,
        TaskStatus.noLongerRelevant,
        TaskStatus.backlog,
      ]);
      expect(TaskStatus.values.map((status) => status.name),
          isNot(contains('pushed')));
      expect(
        TaskStatus.values.map((status) => status.name),
        isNot(contains('skipped')),
      );
    });

    test('manual push preserves durable status and records movement metadata',
        () {
      final task = Task(
        id: 'flexible-1',
        title: 'Clean coffee maker',
        projectId: 'home',
        type: TaskType.flexible,
        status: TaskStatus.planned,
        durationMinutes: 15,
        scheduledStart: DateTime(2026, 6, 24, 9),
        scheduledEnd: DateTime(2026, 6, 24, 9, 15),
        createdAt: now,
        updatedAt: now,
      );

      final result = engine.pushFlexibleTaskToNextAvailableSlot(
        input: SchedulingInput(
          tasks: [task],
          window: SchedulingWindow(
            start: DateTime(2026, 6, 24, 9),
            end: DateTime(2026, 6, 24, 10),
          ),
        ),
        taskId: task.id,
        updatedAt: now.add(const Duration(minutes: 1)),
      );
      final pushed = result.tasks.single;

      expect(pushed.status, TaskStatus.planned);
      expect(pushed.stats.manuallyPushedCount, 1);
      expect(result.changes.single.taskId, task.id);
      expect(result.notices.single.type, SchedulingNoticeType.moved);
    });

    test('burnout skip remains statistics-compatible without a status', () {
      final task = Task.quickCapture(
        id: 'task-1',
        title: 'Fold laundry',
        createdAt: now,
      ).copyWith(
        status: TaskStatus.planned,
        stats: const TaskStatistics().incrementSkippedDuringBurnout(),
      );

      expect(task.status, TaskStatus.planned);
      expect(task.stats.skippedDuringBurnoutCount, 1);
      expect(TaskStatus.values.map((status) => status.name),
          isNot(contains('skipped')));
    });

    test(
        'critical missed moves to backlog while inflexible missed stays in place',
        () {
      final critical = _scheduledRequiredTask(
        id: 'critical-1',
        type: TaskType.critical,
        now: now,
      );
      final inflexible = _scheduledRequiredTask(
        id: 'inflexible-1',
        type: TaskType.inflexible,
        now: now,
      );

      final missedCritical = engine.markMissed(critical, updatedAt: now);
      final missedInflexible = engine.markMissed(inflexible, updatedAt: now);

      expect(missedCritical.status, TaskStatus.backlog);
      expect(missedCritical.scheduledStart, isNull);
      expect(missedCritical.scheduledEnd, isNull);
      expect(missedCritical.stats.missedCount, 1);
      expect(missedCritical.stats.movedToBacklogCount, 1);

      expect(missedInflexible.status, TaskStatus.missed);
      expect(missedInflexible.scheduledStart, inflexible.scheduledStart);
      expect(missedInflexible.scheduledEnd, inflexible.scheduledEnd);
      expect(missedInflexible.stats.missedCount, 1);
      expect(missedInflexible.stats.movedToBacklogCount, 0);
    });
  });
}

/// Top-level helper that performs the `_scheduledRequiredTask` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
Task _scheduledRequiredTask({
  required String id,
  required TaskType type,
  required DateTime now,
}) {
  return Task(
    id: id,
    title: 'Required task',
    projectId: 'home',
    type: type,
    status: TaskStatus.planned,
    durationMinutes: 30,
    scheduledStart: DateTime(2026, 6, 24, 9),
    scheduledEnd: DateTime(2026, 6, 24, 9, 30),
    createdAt: now,
    updatedAt: now,
  );
}
