use anyhow::Result;
use colored::Colorize;
use crate::storage::Storage;
use crate::utils::validation::{resolve_visible_index, visible_indices};
pub fn execute(storage: &impl Storage, id: usize) -> Result<()> {
let tasks = storage.load()?;
let real_index = resolve_visible_index(&tasks, id, |t| t.is_deleted())
.map_err(|_| anyhow::anyhow!("invalid task ID: {}", id))?;
let task = &tasks[real_index];
let vis = visible_indices(&tasks, |t| t.is_deleted());
println!(
"\n{} #{}: {}\n",
"Task".dimmed(),
id,
task.text.bright_white()
);
let vis_id =
|real: usize| -> Option<usize> { vis.iter().position(|&i| i == real).map(|p| p + 1) };
if task.depends_on.is_empty() {
println!("{}", " No dependencies.".dimmed());
} else {
println!("{}:", " Depends on".dimmed());
for dep_uuid in &task.depends_on {
if let Some(real_pos) = tasks.iter().position(|t| t.uuid == *dep_uuid) {
let dep = &tasks[real_pos];
let dep_vis_id = vis_id(real_pos);
let status = if dep.completed {
"✓".green()
} else {
"◦".red()
};
let label = if dep.completed {
dep.text.dimmed()
} else {
dep.text.bright_white()
};
if let Some(did) = dep_vis_id {
println!(" {} #{} — {}", status, did, label);
} else {
println!(" {} [deleted] — {}", status, label);
}
} else {
println!(" {} — {}", "?".yellow(), "(task not found)".dimmed());
}
}
}
let task_uuid = task.uuid;
let dependents: Vec<(usize, &_)> = tasks
.iter()
.enumerate()
.filter(|(i, t)| *i != real_index && t.depends_on.contains(&task_uuid) && !t.is_deleted())
.filter_map(|(real_pos, t)| vis_id(real_pos).map(|vid| (vid, t)))
.collect();
println!();
if dependents.is_empty() {
println!("{}", " No tasks depend on this one.".dimmed());
} else {
println!("{}:", " Required by".dimmed());
for (dep_vis_id, dep_task) in &dependents {
let status = if dep_task.completed {
"✓".green()
} else {
"◦".yellow()
};
println!(
" {} #{} — {}",
status,
dep_vis_id,
dep_task.text.bright_white()
);
}
}
println!();
let visible_tasks: Vec<_> = tasks.iter().filter(|t| !t.is_deleted()).cloned().collect();
if task.is_blocked(&visible_tasks) {
let blocking = task.blocking_deps(&visible_tasks);
let ids = blocking
.iter()
.filter_map(|uuid| {
let real_pos = tasks.iter().position(|t| t.uuid == *uuid)?;
vis_id(real_pos).map(|vid| format!("#{}", vid))
})
.collect::<Vec<_>>()
.join(", ");
println!(" Blocked by: {}", ids.red());
} else if !task.depends_on.is_empty() {
println!(" {} All dependencies satisfied", "✓".green());
}
println!();
Ok(())
}