import 'models.dart';
import 'scheduling_engine.dart';

/// Outcome of a quick-capture request.
enum QuickCaptureStatus {
  addedToBacklog,
  scheduled,
  validationError,
}

/// Input for low-friction task capture.
class QuickCaptureRequest {
  const QuickCaptureRequest({
    required this.id,
    required this.title,
    required this.createdAt,
    this.addToNextAvailableSlot = false,
    this.projectId = 'inbox',
    this.priority = PriorityLevel.medium,
    this.reward = RewardLevel.notSet,
    this.difficulty = DifficultyLevel.notSet,
    this.type = TaskType.flexible,
    this.durationMinutes,
    this.backlogTags = const <BacklogTag>{},
  });

  final String id;
  final String title;
  final DateTime createdAt;
  final bool addToNextAvailableSlot;
  final String projectId;
  final PriorityLevel priority;
  final RewardLevel reward;
  final DifficultyLevel difficulty;
  final TaskType type;
  final int? durationMinutes;
  final Set<BacklogTag> backlogTags;
}

/// Result of a quick-capture request.
class QuickCaptureResult {
  const QuickCaptureResult({
    required this.task,
    required this.status,
    this.schedulingResult,
    this.messages = const <String>[],
  });

  final Task task;
  final QuickCaptureStatus status;
  final SchedulingResult? schedulingResult;
  final List<String> messages;

  bool get isValid => status != QuickCaptureStatus.validationError;
}

/// Coordinates quick capture defaults and optional scheduling.
class QuickCaptureService {
  const QuickCaptureService({this.engine = const SchedulingEngine()});

  final SchedulingEngine engine;

  QuickCaptureResult capture(
    QuickCaptureRequest request, {
    SchedulingInput? schedulingInput,
    DateTime? updatedAt,
  }) {
    final capturedTask = Task.quickCapture(
      id: request.id,
      title: request.title,
      createdAt: request.createdAt,
      projectId: request.projectId,
      type: request.type,
      priority: request.priority,
      reward: request.reward,
      difficulty: request.difficulty,
      backlogTags: request.backlogTags,
      updatedAt: updatedAt,
    ).copyWith(durationMinutes: request.durationMinutes);

    if (!request.addToNextAvailableSlot) {
      return QuickCaptureResult(
        task: capturedTask,
        status: QuickCaptureStatus.addedToBacklog,
      );
    }

    if (request.durationMinutes == null || request.durationMinutes! <= 0) {
      return QuickCaptureResult(
        task: capturedTask,
        status: QuickCaptureStatus.validationError,
        messages: const ['Duration is required to schedule quick capture.'],
      );
    }

    if (request.type != TaskType.flexible) {
      return QuickCaptureResult(
        task: capturedTask,
        status: QuickCaptureStatus.validationError,
        messages: const ['Scheduled quick capture must be flexible.'],
      );
    }

    if (schedulingInput == null) {
      return QuickCaptureResult(
        task: capturedTask,
        status: QuickCaptureStatus.validationError,
        messages: const ['Scheduling input is required.'],
      );
    }

    final result = engine.insertBacklogTaskIntoNextAvailableSlot(
      input: SchedulingInput(
        tasks: [capturedTask, ...schedulingInput.tasks],
        window: schedulingInput.window,
        lockedIntervals: schedulingInput.lockedIntervals,
        requiredVisibleIntervals: schedulingInput.requiredVisibleIntervals,
      ),
      taskId: capturedTask.id,
      updatedAt: updatedAt,
    );
    final scheduledTask = _taskById(result.tasks, capturedTask.id);

    if (scheduledTask == null || scheduledTask.isBacklog) {
      return QuickCaptureResult(
        task: capturedTask,
        status: QuickCaptureStatus.validationError,
        schedulingResult: result,
        messages: result.notices.map((notice) => notice.message).toList(),
      );
    }

    return QuickCaptureResult(
      task: scheduledTask,
      status: QuickCaptureStatus.scheduled,
      schedulingResult: result,
    );
  }
}

Task? _taskById(List<Task> tasks, String id) {
  for (final task in tasks) {
    if (task.id == id) {
      return task;
    }
  }

  return null;
}
