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

/// Tests Required Task Actions 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('Required task action service', () {
    final now = DateTime(2026, 6, 19, 12);
    const service = RequiredTaskActionService();

    test('done marks inflexible task completed without clearing history', () {
      final task = requiredTask(
        id: 'appointment',
        type: TaskType.inflexible,
        createdAt: now,
        start: DateTime(2026, 6, 19, 9),
      );

      final result = service.apply(
        task: task,
        action: RequiredTaskAction.done,
        updatedAt: now,
      );

      expect(result.action, RequiredTaskAction.done);
      expect(result.task.status, TaskStatus.completed);
      expect(result.task.scheduledStart, task.scheduledStart);
      expect(result.task.scheduledEnd, task.scheduledEnd);
      expect(result.removedFromActivePlan, isFalse);
    });

    test('done marks critical task completed without moving it', () {
      final task = requiredTask(
        id: 'meds',
        type: TaskType.critical,
        createdAt: now,
        start: DateTime(2026, 6, 19, 10),
      );

      final result = service.apply(
        task: task,
        action: RequiredTaskAction.done,
        updatedAt: now,
      );

      expect(result.task.status, TaskStatus.completed);
      expect(result.task.scheduledStart, task.scheduledStart);
      expect(result.task.scheduledEnd, task.scheduledEnd);
    });

    test('missed critical task moves to backlog and clears schedule', () {
      final task = requiredTask(
        id: 'critical',
        type: TaskType.critical,
        createdAt: now,
        start: DateTime(2026, 6, 19, 9),
      );

      final result = service.apply(
        task: task,
        action: RequiredTaskAction.missed,
        updatedAt: now,
      );

      expect(result.task.status, TaskStatus.backlog);
      expect(result.task.scheduledStart, isNull);
      expect(result.task.scheduledEnd, isNull);
      expect(result.task.stats.missedCount, 1);
      expect(result.task.stats.movedToBacklogCount, 1);
      expect(result.removedFromActivePlan, isTrue);
    });

    test('missed inflexible task remains scheduled as history', () {
      final task = requiredTask(
        id: 'appointment',
        type: TaskType.inflexible,
        createdAt: now,
        start: DateTime(2026, 6, 19, 9),
      );

      final result = service.apply(
        task: task,
        action: RequiredTaskAction.missed,
        updatedAt: now,
      );

      expect(result.task.status, TaskStatus.missed);
      expect(result.task.scheduledStart, task.scheduledStart);
      expect(result.task.scheduledEnd, task.scheduledEnd);
      expect(result.task.stats.missedCount, 1);
      expect(result.removedFromActivePlan, isFalse);
    });

    test('cancel and no-longer-relevant remain distinct states', () {
      final task = requiredTask(
        id: 'appointment',
        type: TaskType.inflexible,
        createdAt: now,
        start: DateTime(2026, 6, 19, 9),
      );

      final cancelled = service.apply(
        task: task,
        action: RequiredTaskAction.cancel,
        updatedAt: now,
      );
      final noLongerRelevant = service.apply(
        task: task,
        action: RequiredTaskAction.noLongerRelevant,
        updatedAt: now,
      );

      expect(cancelled.task.status, TaskStatus.cancelled);
      expect(cancelled.task.scheduledStart, isNull);
      expect(cancelled.task.scheduledEnd, isNull);
      expect(cancelled.task.stats.cancelledCount, 1);
      expect(cancelled.removedFromActivePlan, isTrue);

      expect(noLongerRelevant.task.status, TaskStatus.noLongerRelevant);
      expect(noLongerRelevant.task.scheduledStart, isNull);
      expect(noLongerRelevant.task.scheduledEnd, isNull);
      expect(noLongerRelevant.task.stats.cancelledCount, 0);
      expect(noLongerRelevant.removedFromActivePlan, isTrue);
    });

    test('required action service rejects flexible tasks', () {
      final task = Task.quickCapture(
        id: 'flexible',
        title: 'Flexible',
        createdAt: now,
      ).copyWith(status: TaskStatus.planned);

      expect(
        () => service.apply(
          task: task,
          action: RequiredTaskAction.done,
          updatedAt: now,
        ),
        throwsArgumentError,
      );
    });

    test('required action service rejects locked tasks', () {
      final task = requiredTask(
        id: 'locked',
        type: TaskType.locked,
        createdAt: now,
        start: DateTime(2026, 6, 19, 9),
      );

      expect(
        () => service.apply(
          task: task,
          action: RequiredTaskAction.missed,
          updatedAt: now,
        ),
        throwsArgumentError,
      );
    });
  });
}

/// Runs the `requiredTask` top-level operation.
/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior.
Task requiredTask({
  required String id,
  required TaskType type,
  required DateTime createdAt,
  required DateTime start,
}) {
  return Task(
    id: id,
    title: id,
    projectId: 'required',
    type: type,
    status: TaskStatus.planned,
    priority: PriorityLevel.high,
    durationMinutes: 30,
    scheduledStart: start,
    scheduledEnd: start.add(const Duration(minutes: 30)),
    createdAt: createdAt,
    updatedAt: createdAt,
  );
}
