import 'task_statistics.dart';

/// Scheduling behavior category.
enum TaskType {
  /// Movable planned work.
  flexible,

  /// Required visible block that should not be moved automatically.
  inflexible,

  /// Required visible task that remains actionable if missed.
  critical,

  /// Hidden scheduling constraint, not a task card.
  locked,

  /// Unplanned completed/logged task.
  surprise,

  /// Intentional rest time.
  freeSlot,
}

/// Current lifecycle state of a task.
enum TaskStatus {
  /// Scheduled or queued work that has not started.
  planned,

  /// Work currently in progress.
  active,

  /// Work finished by the user.
  completed,

  /// Work that was not completed in its intended time.
  missed,

  /// Work intentionally removed from the plan.
  cancelled,

  /// Work intentionally dismissed because it no longer applies.
  noLongerRelevant,

  /// Unscheduled work kept for later planning.
  backlog,
}

/// User-facing importance level.
enum PriorityLevel {
  /// Lowest priority.
  veryLow,

  /// Low priority.
  low,

  /// Default middle priority.
  medium,

  /// High priority.
  high,

  /// Highest priority.
  veryHigh,
}

/// Expected reward or payoff from completing a task.
enum RewardLevel {
  /// No reward level has been captured; this is not equivalent to low reward.
  notSet,

  /// Very low expected reward.
  veryLow,

  /// Low expected reward.
  low,

  /// Medium expected reward.
  medium,

  /// High expected reward.
  high,

  /// Very high expected reward.
  veryHigh,
}

/// Expected effort or activation difficulty for a task.
enum DifficultyLevel {
  /// No difficulty has been captured yet.
  notSet,

  /// Very easy to start or complete.
  veryEasy,

  /// Easy to start or complete.
  easy,

  /// Medium effort.
  medium,

  /// Hard to start or complete.
  hard,

  /// Very hard to start or complete.
  veryHard,
}

/// Reminder intensity preference.
enum ReminderProfile {
  /// No reminder nudges.
  silent,

  /// Low-friction reminder nudges.
  gentle,

  /// Repeated reminder nudges.
  persistent,

  /// Strong reminder behavior for required items.
  strict,
}

/// Lightweight backlog-only metadata.
enum BacklogTag {
  /// Task is intentionally saved as a someday/wishlist item.
  wishlist,
}

/// Starter task model for the scheduling core.
///
/// This is a public placeholder API for early V1 chunks. Keep behavior changes
/// explicit and covered by tests as the model becomes more complete.
class Task {
  const Task({
    required this.id,
    required this.title,
    required this.projectId,
    required this.type,
    required this.status,
    required this.createdAt,
    required this.updatedAt,
    this.priority,
    this.reward = RewardLevel.notSet,
    this.difficulty = DifficultyLevel.notSet,
    this.durationMinutes,
    this.scheduledStart,
    this.scheduledEnd,
    this.parentTaskId,
    this.backlogTags = const <BacklogTag>{},
    this.stats = const TaskStatistics(),
  });

  /// Create a minimal captured task without requiring planning details.
  factory Task.quickCapture({
    required String id,
    required String title,
    required DateTime createdAt,
    String projectId = 'inbox',
    TaskType type = TaskType.flexible,
    TaskStatus status = TaskStatus.backlog,
    PriorityLevel priority = PriorityLevel.medium,
    RewardLevel reward = RewardLevel.notSet,
    DifficultyLevel difficulty = DifficultyLevel.notSet,
    Set<BacklogTag> backlogTags = const <BacklogTag>{},
    DateTime? updatedAt,
  }) {
    if (title.trim().isEmpty) {
      throw ArgumentError.value(title, 'title', 'Title is required.');
    }

    return Task(
      id: id,
      title: title.trim(),
      projectId: projectId,
      type: type,
      status: status,
      priority: priority,
      reward: reward,
      difficulty: difficulty,
      createdAt: createdAt,
      updatedAt: updatedAt ?? createdAt,
      backlogTags: backlogTags,
    );
  }

  final String id;
  final String title;
  final String projectId;
  final TaskType type;
  final TaskStatus status;
  final PriorityLevel? priority;
  final RewardLevel reward;
  final DifficultyLevel difficulty;
  final int? durationMinutes;
  final DateTime? scheduledStart;
  final DateTime? scheduledEnd;
  final String? parentTaskId;
  final Set<BacklogTag> backlogTags;
  final DateTime createdAt;
  final DateTime updatedAt;
  final TaskStatistics stats;

  bool get isFlexible => type == TaskType.flexible;
  bool get isRequiredVisible =>
      type == TaskType.critical || type == TaskType.inflexible;
  bool get isLocked => type == TaskType.locked;
  bool get isBacklog => status == TaskStatus.backlog;

  Task copyWith({
    String? id,
    String? title,
    String? projectId,
    TaskType? type,
    TaskStatus? status,
    PriorityLevel? priority,
    RewardLevel? reward,
    DifficultyLevel? difficulty,
    int? durationMinutes,
    DateTime? scheduledStart,
    DateTime? scheduledEnd,
    String? parentTaskId,
    Set<BacklogTag>? backlogTags,
    DateTime? createdAt,
    DateTime? updatedAt,
    TaskStatistics? stats,
    bool clearSchedule = false,
  }) {
    return Task(
      id: id ?? this.id,
      title: title ?? this.title,
      projectId: projectId ?? this.projectId,
      type: type ?? this.type,
      status: status ?? this.status,
      priority: priority ?? this.priority,
      reward: reward ?? this.reward,
      difficulty: difficulty ?? this.difficulty,
      durationMinutes: durationMinutes ?? this.durationMinutes,
      scheduledStart:
          clearSchedule ? null : (scheduledStart ?? this.scheduledStart),
      scheduledEnd: clearSchedule ? null : (scheduledEnd ?? this.scheduledEnd),
      parentTaskId: parentTaskId ?? this.parentTaskId,
      backlogTags: backlogTags ?? this.backlogTags,
      createdAt: createdAt ?? this.createdAt,
      updatedAt: updatedAt ?? this.updatedAt,
      stats: stats ?? this.stats,
    );
  }
}

/// Starter project defaults used when creating or scheduling tasks.
class ProjectProfile {
  const ProjectProfile({
    required this.id,
    required this.name,
    required this.colorKey,
    this.defaultPriority = PriorityLevel.medium,
    this.defaultReward = RewardLevel.notSet,
    this.defaultDifficulty = DifficultyLevel.notSet,
    this.defaultReminderProfile = ReminderProfile.gentle,
    this.defaultDurationMinutes,
  });

  final String id;
  final String name;
  final String colorKey;
  final PriorityLevel defaultPriority;
  final RewardLevel defaultReward;
  final DifficultyLevel defaultDifficulty;
  final ReminderProfile defaultReminderProfile;
  final int? defaultDurationMinutes;

  /// Create a task using project defaults while allowing explicit overrides.
  Task createTask({
    required String id,
    required String title,
    required DateTime createdAt,
    TaskType type = TaskType.flexible,
    TaskStatus status = TaskStatus.backlog,
    PriorityLevel? priority,
    RewardLevel? reward,
    DifficultyLevel? difficulty,
    int? durationMinutes,
    DateTime? scheduledStart,
    DateTime? scheduledEnd,
    String? parentTaskId,
    Set<BacklogTag> backlogTags = const <BacklogTag>{},
    DateTime? updatedAt,
  }) {
    return Task(
      id: id,
      title: title,
      projectId: this.id,
      type: type,
      status: status,
      priority: priority ?? defaultPriority,
      reward: reward ?? defaultReward,
      difficulty: difficulty ?? defaultDifficulty,
      durationMinutes: durationMinutes ?? defaultDurationMinutes,
      scheduledStart: scheduledStart,
      scheduledEnd: scheduledEnd,
      parentTaskId: parentTaskId,
      backlogTags: backlogTags,
      createdAt: createdAt,
      updatedAt: updatedAt ?? createdAt,
    );
  }
}

/// Starter time range value used by scheduling helpers.
class TimeInterval {
  const TimeInterval({
    required this.start,
    required this.end,
    this.label,
  });

  final DateTime start;
  final DateTime end;
  final String? label;

  Duration get duration => end.difference(start);

  bool overlaps(TimeInterval other) {
    return start.isBefore(other.end) && end.isAfter(other.start);
  }
}
