//! `relicario list` and `relicario history` — both read-only browse paths.

use anyhow::Result;

pub fn cmd_list(
    type_filter: Option<String>,
    group_filter: Option<String>,
    tag_filter: Option<String>,
    trashed: bool,
) -> Result<()> {
    use relicario_core::ItemType;

    let vault = crate::session::UnlockedVault::unlock_interactive()?;
    let manifest = vault.load_manifest()?;

    let parsed_type: Option<ItemType> = match type_filter.as_deref() {
        None => None,
        Some("login") => Some(ItemType::Login),
        Some("secure_note") | Some("note") => Some(ItemType::SecureNote),
        Some("identity") => Some(ItemType::Identity),
        Some("card") => Some(ItemType::Card),
        Some("key") => Some(ItemType::Key),
        Some("document") => Some(ItemType::Document),
        Some("totp") => Some(ItemType::Totp),
        Some(other) => anyhow::bail!("unknown type filter: {other}"),
    };

    let mut entries: Vec<_> = manifest.items.values()
        .filter(|e| {
            if trashed { e.trashed_at.is_some() } else { e.trashed_at.is_none() }
        })
        .filter(|e| match parsed_type {
            Some(t) => e.r#type == t,
            None => true,
        })
        .filter(|e| group_filter.as_ref().is_none_or(|g| e.group.as_deref() == Some(g.as_str())))
        .filter(|e| tag_filter.as_ref().is_none_or(|t| e.tags.iter().any(|x| x == t)))
        .collect();
    entries.sort_by(|a, b| a.title.to_lowercase().cmp(&b.title.to_lowercase()));

    if entries.is_empty() {
        eprintln!("(no items match)");
        return Ok(());
    }

    println!("{:<16}  {:<14}  {:<6}  TITLE", "ID", "TYPE", "FAV");
    for e in entries {
        let fav = if e.favorite { "  *" } else { "" };
        println!("{:<16}  {:<14}  {:<6}  {}", e.id.as_str(), format!("{:?}", e.r#type), fav, e.title);
    }
    Ok(())
}

pub fn cmd_history(query: String, show: bool, field: Option<String>) -> Result<()> {
    let vault = crate::session::UnlockedVault::unlock_interactive()?;
    let manifest = vault.load_manifest()?;
    let entry = super::resolve_query(&manifest, &query)?;
    let item = vault.load_item(&entry.id)?;

    println!("History for {} ({})", item.title, item.id.as_str());
    println!();

    // Filter and sort the field-id keys so output is deterministic.
    let mut keys: Vec<&relicario_core::FieldId> = item.field_history.keys().collect();
    keys.sort_by(|a, b| a.0.cmp(&b.0));

    let mut printed_any = false;
    for fid in keys {
        let display_name = fid.0.strip_prefix("core:").unwrap_or(&fid.0);
        if let Some(filter) = &field {
            if display_name != filter && fid.0 != *filter { continue; }
        }
        let entries = &item.field_history[fid];
        if entries.is_empty() { continue; }
        printed_any = true;

        println!("{display_name} ({} {})",
                 entries.len(),
                 if entries.len() == 1 { "entry" } else { "entries" });
        for (i, e) in entries.iter().enumerate() {
            let ts = crate::helpers::iso8601(e.replaced_at);
            if show {
                println!("  [{i}] {ts}  {}", e.value.as_str());
            } else {
                println!("  [{i}] {ts}  ********");
            }
        }
        println!();
    }

    if !printed_any {
        if field.is_some() {
            println!("no history for the requested field");
        } else {
            println!("no history captured for this item");
        }
    } else if !show {
        println!("(use --show to reveal values)");
    }

    Ok(())
}
