import 'models.dart';

/// Derived backlog filters for a unified backlog list.
enum BacklogFilter {
  inbox,
  pushed,
  criticalMissed,
  wishlist,
  stale,
  noRewardSet,
}

/// Sort options for a unified backlog list.
enum BacklogSortKey {
  priority,
  rewardVsEffort,
  age,
  project,
  timesPushed,
}

/// Visual age bucket for backlog display.
enum BacklogStalenessMarker {
  green,
  blue,
  purple,
}

/// Configurable thresholds for backlog age markers.
class BacklogStalenessSettings {
  const BacklogStalenessSettings({
    this.greenMaxAge = const Duration(days: 7),
    this.blueMaxAge = const Duration(days: 30),
  });

  final Duration greenMaxAge;
  final Duration blueMaxAge;

  BacklogStalenessMarker markerFor({
    required Task task,
    required DateTime now,
  }) {
    final age = now.difference(task.createdAt);

    if (age <= greenMaxAge) {
      return BacklogStalenessMarker.green;
    }

    if (age <= blueMaxAge) {
      return BacklogStalenessMarker.blue;
    }

    return BacklogStalenessMarker.purple;
  }
}

/// Read-only backlog projection over the unified task list.
class BacklogView {
  const BacklogView({
    required this.tasks,
    required this.now,
    this.staleAfter = const Duration(days: 31),
    this.stalenessSettings = const BacklogStalenessSettings(),
  });

  final List<Task> tasks;
  final DateTime now;
  final Duration staleAfter;
  final BacklogStalenessSettings stalenessSettings;

  List<Task> get backlogTasks {
    return tasks.where((task) => task.isBacklog).toList(growable: false);
  }

  List<Task> filter(BacklogFilter filter) {
    return backlogTasks.where((task) => _matchesFilter(task, filter)).toList(
          growable: false,
        );
  }

  List<Task> sorted(BacklogSortKey sortKey) {
    final sortedTasks = [...backlogTasks];
    sortedTasks.sort((a, b) => _compareTasks(a, b, sortKey));

    return List<Task>.unmodifiable(sortedTasks);
  }

  BacklogStalenessMarker stalenessMarkerFor(Task task) {
    return stalenessSettings.markerFor(task: task, now: now);
  }

  bool _matchesFilter(Task task, BacklogFilter filter) {
    return switch (filter) {
      BacklogFilter.inbox => task.projectId == 'inbox',
      BacklogFilter.pushed =>
        task.stats.manuallyPushedCount > 0 || task.stats.autoPushedCount > 0,
      BacklogFilter.criticalMissed =>
        task.type == TaskType.critical && task.stats.missedCount > 0,
      BacklogFilter.wishlist => task.backlogTags.contains(BacklogTag.wishlist),
      BacklogFilter.stale => now.difference(task.updatedAt) >= staleAfter,
      BacklogFilter.noRewardSet => task.reward == RewardLevel.notSet,
    };
  }

  int _compareTasks(Task a, Task b, BacklogSortKey sortKey) {
    return switch (sortKey) {
      BacklogSortKey.priority =>
        _priorityRank(b.priority).compareTo(_priorityRank(a.priority)),
      BacklogSortKey.rewardVsEffort =>
        _rewardVsEffortScore(b).compareTo(_rewardVsEffortScore(a)),
      BacklogSortKey.age => a.createdAt.compareTo(b.createdAt),
      BacklogSortKey.project => a.projectId.compareTo(b.projectId),
      BacklogSortKey.timesPushed => _timesPushed(b).compareTo(_timesPushed(a)),
    };
  }
}

int _priorityRank(PriorityLevel? priority) {
  return switch (priority) {
    PriorityLevel.veryLow => 0,
    PriorityLevel.low => 1,
    PriorityLevel.medium || null => 2,
    PriorityLevel.high => 3,
    PriorityLevel.veryHigh => 4,
  };
}

int _rewardRank(RewardLevel reward) {
  return switch (reward) {
    RewardLevel.notSet => 0,
    RewardLevel.veryLow => 1,
    RewardLevel.low => 2,
    RewardLevel.medium => 3,
    RewardLevel.high => 4,
    RewardLevel.veryHigh => 5,
  };
}

int _difficultyRank(DifficultyLevel difficulty) {
  return switch (difficulty) {
    DifficultyLevel.notSet => 0,
    DifficultyLevel.veryEasy => 1,
    DifficultyLevel.easy => 2,
    DifficultyLevel.medium => 3,
    DifficultyLevel.hard => 4,
    DifficultyLevel.veryHard => 5,
  };
}

int _rewardVsEffortScore(Task task) {
  return _rewardRank(task.reward) - _difficultyRank(task.difficulty);
}

int _timesPushed(Task task) {
  return task.stats.manuallyPushedCount + task.stats.autoPushedCount;
}
