tasker-cli 2.2.1

A To-Do CLI application for managing your daily Tasks.
Documentation
use crate::{
    cli::{ListTasks, SortTasks},
    config::{Configuration, Language},
};
use indexmap::IndexSet;
use itertools::Itertools;
use lib_tasker::todos::{State, Task, ToDo};
use owo_colors::OwoColorize;

#[must_use]
pub fn get_next_index(to_do: &ToDo) -> usize {
    to_do.tasks.last().map_or(0, |last| last.id + 1)
}

fn push_task(task: &Task, string: &mut String, config: &Configuration) {
    string.push_str(&format!("{}. {}\n", task.id.purple(), task.description));

    match config.language {
        Language::English => match task.state {
            State::ToDo => string.push_str(&format!("[{}] ", "To-Do".blue())),
            State::Doing => {
                string.push_str(&format!("[{}] ", "Doing".yellow()));
            }
            State::Done => string.push_str(&format!("[{}] ", "Done".green())),
            State::Waiting => {
                string.push_str(&format!("[{}] ", "Waiting".red()));
            }
        },
        Language::Spanish => match task.state {
            State::ToDo => {
                string.push_str(&format!("[{}] ", "Por Hacer".blue()));
            }
            State::Doing => {
                string.push_str(&format!("[{}] ", "Haciendo".yellow()));
            }
            State::Done => string.push_str(&format!("[{}] ", "Hecho".green())),
            State::Waiting => {
                string.push_str(&format!("[{}] ", "Esperando".red()));
            }
        },
    }

    string.push_str("{ ");
    let tags = task.tags.iter().join(", ");
    string.push_str(&tags);
    string.push_str(" }\n\n");
}

pub fn list_to_dos(
    to_do: ToDo,
    config: &Configuration,
    args: Option<ListTasks>,
) {
    let mut output = String::new();

    if let Some(options) = args {
        let mut tasks = to_do.tasks;

        if let Some(description) = options.description {
            tasks.retain(|task| {
                task.description
                    .to_lowercase()
                    .contains(&description.to_lowercase())
            });
        }

        if let Some(state) = options.state {
            tasks.retain(|task| task.state == state.into());
        }

        if let Some(tags) = options.tag {
            let tags: IndexSet<String> = tags.into_iter().collect();
            tasks.retain(|task| task.tags.intersection(&tags).count() > 0);
        }

        if let Some(project) = options.project {
            tasks.retain(|task| {
                task.project
                    .to_lowercase()
                    .contains(&project.to_lowercase())
            });
        }

        if let Some(sort_options) = options.sort_by {
            match sort_options {
                SortTasks::Description => tasks.sort_unstable_by(|a, b| {
                    a.description
                        .to_lowercase()
                        .cmp(&b.description.to_lowercase())
                }),
                SortTasks::Project => tasks.sort_unstable_by(|a, b| {
                    a.project.to_lowercase().cmp(&b.project.to_lowercase())
                }),
                SortTasks::ID => tasks.sort_unstable_by(|a, b| a.id.cmp(&b.id)),
                SortTasks::State => {
                    tasks.sort_unstable_by(|a, b| a.state.cmp(&b.state));
                }
            }
        }

        tasks
            .iter()
            .for_each(|task| push_task(task, &mut output, config));
    } else {
        match config.language {
            Language::English => output.push_str(&format!(
                "Hello, {}!\nHere's what you got for today:\n",
                config.name
            )),
            Language::Spanish => output.push_str(&format!(
                "¡Hola, {}!\nEsto es lo que tienes para hoy:\n",
                config.name
            )),
        }

        output.push('\n');

        let projects = to_do
            .tasks
            .iter()
            .unique_by(|task| &task.project)
            .map(|task| task.project.clone())
            .sorted();

        for project in projects {
            output.push_str(&format!("{}\n\n", project.purple().underline()));

            to_do
                .tasks
                .iter()
                .filter(|task| task.project == project)
                .for_each(|task| push_task(task, &mut output, config));
        }
    }

    print!("{output}");
}