//! Queue sort subcommand.
//!
//! Purpose:
//! - Queue sort subcommand.
//!
//! Responsibilities:
//! - Reorder tasks in .cueloop/queue.jsonc by priority.
//! - Support dry-run mode to preview the new order.
//!
//! Not handled here:
//! - Time-based or complex sorting (use `cueloop queue list --sort-by` for that).
//! - Sorting by arbitrary fields (intentionally limited to prevent footguns).
//!
//!
//! Usage:
//! - Used through the crate module tree or integration test harness.
//!
//! Invariants/assumptions:
//! - Only supports priority sorting to avoid dangerous queue reordering.
//! - Mutates queue.json; use with care in collaborative environments.
//! - Dry-run mode does NOT create undo snapshots or write to disk.
use anyhow::Result;
use clap::Args;
use crate::config::Resolved;
use crate::queue;
use super::{QueueSortBy, QueueSortOrder};
/// Arguments for `cueloop queue sort`.
#[derive(Args)]
#[command(
after_long_help = "Examples:\n cueloop queue sort\n cueloop queue sort --order descending\n cueloop queue sort --order ascending\n cueloop queue sort --dry-run\n cueloop queue list --scheduled --sort-by scheduled_start --order ascending\n\nDry run:\n Shows the new queue order without modifying files.\n\nNote:\n - `cueloop queue sort` reorders .cueloop/queue.jsonc and intentionally supports priority only.\n - For triage/time-based sorting without mutating files, use `cueloop queue list --sort-by ...`."
)]
pub struct QueueSortArgs {
/// Sort by field (supported: priority only; reorders queue file).
#[arg(long, value_enum, default_value_t = QueueSortBy::Priority)]
pub sort_by: QueueSortBy,
/// Sort order (default: descending, highest priority first).
#[arg(long, value_enum, default_value_t = QueueSortOrder::Descending)]
pub order: QueueSortOrder,
/// Show what would change without writing to disk.
#[arg(long)]
pub dry_run: bool,
}
pub(crate) fn handle(resolved: &Resolved, force: bool, args: QueueSortArgs) -> Result<()> {
let _queue_lock = queue::acquire_queue_lock(&resolved.repo_root, "queue sort", force)?;
// Create undo snapshot before mutation (only if not dry-run)
if !args.dry_run {
crate::undo::create_undo_snapshot(resolved, &format!("queue sort by {}", args.sort_by))?;
}
let mut queue_file = queue::load_queue(&resolved.queue_path)?;
// Capture original order for dry-run comparison
let original_ids: Vec<String> = queue_file.tasks.iter().map(|t| t.id.clone()).collect();
match args.sort_by {
QueueSortBy::Priority => {
queue::sort_tasks_by_priority(&mut queue_file, args.order.is_descending());
}
}
if args.dry_run {
let new_ids: Vec<String> = queue_file.tasks.iter().map(|t| t.id.clone()).collect();
if original_ids == new_ids {
log::info!("Dry run: queue is already sorted (no changes).");
} else {
log::info!("Dry run: would reorder {} task(s).", new_ids.len());
log::info!("New order: {}", new_ids.join(", "));
}
} else {
queue::save_queue(&resolved.queue_path, &queue_file)?;
log::info!("Queue sorted by {} (order: {}).", args.sort_by, args.order);
}
Ok(())
}