use crate::config::Config;
use crate::date_parse;
use crate::store::Store;
use anyhow::{bail, Result};
use chrono::{Local, NaiveDate};
use colored::Colorize;
use std::collections::HashMap;

/// Update an element's typed attributes in-place.
pub fn run(
    config: &Config,
    ref_path: &str,
    status: Option<String>,
    start_time: Option<String>,
    end_time: Option<String>,
    at: Option<String>,
    date: Option<String>,
) -> Result<()> {
    let mut new_attrs: HashMap<String, String> = HashMap::new();
    if let Some(s) = status {
        new_attrs.insert("status".into(), s);
    }
    if let Some(s) = start_time {
        new_attrs.insert("start".into(), s);
    }
    if let Some(e) = end_time {
        new_attrs.insert("end".into(), e);
    }
    if let Some(a) = at {
        new_attrs.insert("at".into(), a);
    }

    if new_attrs.is_empty() {
        bail!("No attributes specified. Use --status, --start-time, --end-time, or --at.");
    }

    let d = resolve_date(date)?;
    let store = Store::new(&config.storage_dir);

    match store.rewrite_element(ref_path, &new_attrs, d)? {
        true => println!("  {} {}", "updated".green(), ref_path),
        false => bail!("Could not update '{}'. Check the ref is correct.", ref_path),
    }
    Ok(())
}

/// Mark a task as done — shorthand for `update REFPATH --status done`.
pub fn run_done(config: &Config, ref_path: &str, date: Option<String>) -> Result<()> {
    let mut new_attrs = HashMap::new();
    new_attrs.insert("status".into(), "done".into());

    let d = store_date(date)?;
    let store = Store::new(&config.storage_dir);

    match store.rewrite_element(ref_path, &new_attrs, d)? {
        true => println!("  {} {}", "done".green(), ref_path),
        false => bail!(
            "Could not mark '{}' as done. Check the ref is correct.",
            ref_path
        ),
    }
    Ok(())
}

fn resolve_date(date: Option<String>) -> Result<NaiveDate> {
    match date {
        Some(s) => Ok(date_parse::parse_date(&s)?),
        None => Ok(Local::now().date_naive()),
    }
}

fn store_date(date: Option<String>) -> Result<NaiveDate> {
    resolve_date(date)
}
