backburner 0.1.2

Private project memory for work worth coming back to.
use anyhow::Result;
use serde::Serialize;

use crate::models::{Context, TaskDetails, TaskStatus};
use crate::repository::FinishSessionResult;

pub fn json<T: Serialize>(value: &T) -> Result<()> {
    println!("{}", serde_json::to_string_pretty(value)?);
    Ok(())
}

pub fn list(title: &str, tasks: &[TaskDetails]) {
    println!("{title}");
    if tasks.is_empty() {
        println!("\nNothing here.");
        return;
    }
    println!();
    for details in tasks {
        print_task_line(details);
    }
}

pub fn show(details: &TaskDetails) {
    println!("#{} {}", details.task.id, details.task.title);
    println!("Status: {}", details.task.status);
    if let Some(planned) = &details.task.planned_date_key {
        println!("Planned: {planned}");
    }
    if details.task.completed_at.is_some() {
        println!("Completed: yes");
    }
    if !details.notes.is_empty() {
        println!("\nNotes:");
        for note in &details.notes {
            println!("- {}", note.body);
        }
    }
    if !details.files.is_empty() {
        println!("\nFiles:");
        for file in &details.files {
            match file.line {
                Some(line) => println!("- {}:{line}", file.path),
                None => println!("- {}", file.path),
            }
        }
    }
    if !details.commands.is_empty() {
        println!("\nCommands:");
        for command in &details.commands {
            println!("- {}", command.command);
        }
    }
}

pub fn context(context: &Context) {
    if context.promoted > 0 {
        println!("Promoted {} planned task(s).\n", context.promoted);
    }
    list("Today", &context.today);
    println!();
    let backburner = context
        .backburner
        .iter()
        .take(8)
        .cloned()
        .collect::<Vec<_>>();
    list("Backburner", &backburner);
}

pub fn finish_session(result: &FinishSessionResult) {
    println!(
        "Archived {} completed task(s). Moved {} unfinished task(s) to Backburner.",
        result.archived, result.backburnered
    );
}

pub fn moved(id: i64, status: TaskStatus) {
    println!("Moved #{id} to {status}.");
}

fn print_task_line(details: &TaskDetails) {
    let check = if details.task.completed_at.is_some() {
        "[x]"
    } else {
        "[ ]"
    };
    let planned = details
        .task
        .planned_date_key
        .as_ref()
        .map(|value| format!(" ({value})"))
        .unwrap_or_default();
    println!(
        "{check} #{} {}{}",
        details.task.id, details.task.title, planned
    );
    for file in details.files.iter().take(2) {
        match file.line {
            Some(line) => println!("    {}:{line}", file.path),
            None => println!("    {}", file.path),
        }
    }
    if let Some(command) = details.commands.first() {
        println!("    {}", command.command);
    }
}