complish 0.0.1

Core library for project-aware task management with git integration
Documentation
use eyre::{Result, eyre};

use crate::{Task, TaskPriority, Vault};

pub struct TaskBuilder<'a> {
  list_name: String,
  project_id: Option<u32>,
  task: Task,
  vault: &'a mut Vault,
}

impl<'a> TaskBuilder<'a> {
  pub fn new(vault: &'a mut Vault, subject: impl Into<String>) -> Self {
    let canonical_id = &vault.index.peek_next_canonical_id();
    let friendly_id = &format!("{}", &vault.index.peek_next_friendly_id_by_default());
    let task = Task::new(*canonical_id, friendly_id, subject);

    Self {
      list_name: String::from("someday"),
      project_id: None,
      task,
      vault,
    }
  }

  pub fn create(&mut self) -> Result<Task> {
    self.task.id = self.vault.index.allocate_canonical_id();

    if self.project_id.is_none() {
      self.task.friendly_id = format!("{}", self.vault.index.allocate_friendly_id_for_default());
    } else {
      self.task.friendly_id = format!(
        "{}",
        self
          .vault
          .index
          .allocate_friendly_id_for_project(self.project_id.unwrap())
      );
      let project = self
        .vault
        .projects
        .get_mut(&self.project_id.unwrap())
        .unwrap();
      project.task_ids.push(self.task.id);
    }

    self
      .vault
      .index
      .register_task(&self.task, &self.list_name, self.project_id);
    self.vault.tasks.insert(self.task.id, self.task.clone());
    let list = self.vault.task_lists.get_mut(&self.list_name).unwrap();
    list.task_ids.push(self.task.id);
    self.vault.save()?;

    Ok(self.task.clone())
  }

  pub fn for_project(mut self, project_key: impl Into<String>) -> Result<Self> {
    let key = project_key.into();
    let project_id = self
      .vault
      .index
      .get_canonical_project_id_from_key(&key)
      .ok_or_else(|| eyre!("Project with key '{}' not found", key))?;

    let next_project_id = self
      .vault
      .index
      .peek_next_friendly_id_by_project(project_id);
    self.task.friendly_id = format!("{}-{}", &key, &next_project_id);
    self.project_id = Some(project_id);
    Ok(self)
  }

  pub fn in_list(mut self, list_name: impl Into<String>) -> Result<Self> {
    self.list_name = list_name.into();
    if !self.vault.task_lists.contains_key(&self.list_name) {
      return Err(eyre!(
        "List '{}' not found. Must be one of: {}",
        self.list_name,
        self
          .vault
          .task_lists
          .keys()
          .map(String::as_str)
          .collect::<Vec<_>>()
          .join(", ")
      ));
    }

    Ok(self)
  }

  pub fn with_description(mut self, description: impl Into<String>) -> Self {
    self.task.description = Some(description.into());
    self
  }

  pub fn with_priority(mut self, priority: TaskPriority) -> Self {
    self.task.priority = priority;
    self
  }
}