//! `relicario get` — print a single item, masking secrets unless `--show`.

use anyhow::{Context, Result};

pub fn cmd_get(query: String, show: bool, copy: bool) -> Result<()> {
    use relicario_core::ItemCore;
    use zeroize::Zeroizing;

    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!("ID:       {}", item.id.as_str());
    println!("Title:    {}", item.title);
    println!("Type:     {:?}", item.r#type);
    if let Some(g) = &item.group { println!("Group:    {g}"); }
    if !item.tags.is_empty() { println!("Tags:     {}", item.tags.join(", ")); }
    println!("Created:  {}", crate::helpers::iso8601(item.created));
    println!("Modified: {}", crate::helpers::iso8601(item.modified));
    if let Some(t) = item.trashed_at { println!("Trashed:  {}", crate::helpers::iso8601(t)); }
    println!();

    let primary_secret: Option<Zeroizing<String>> = match &item.core {
        ItemCore::Login(l) => {
            if let Some(u) = &l.username { println!("Username: {u}"); }
            if let Some(u) = &l.url { println!("URL:      {u}"); }
            if let Some(t) = &l.totp {
                if show {
                    println!("TOTP:     {}", data_encoding::BASE32.encode(&t.secret));
                } else {
                    println!("TOTP:     ****  (use --show to reveal)");
                }
            }
            l.password.clone()
        }
        ItemCore::SecureNote(n) => {
            if show { println!("Body:\n{}", n.body.as_str()); }
            else { println!("Body:     ********"); }
            None
        }
        ItemCore::Identity(i) => {
            if let Some(v) = &i.full_name { println!("Name:     {v}"); }
            if let Some(v) = &i.email { println!("Email:    {v}"); }
            if let Some(v) = &i.phone { println!("Phone:    {v}"); }
            if let Some(v) = &i.date_of_birth { println!("DOB:      {v}"); }
            None
        }
        ItemCore::Card(c) => {
            if let Some(h) = &c.holder { println!("Holder:   {h}"); }
            if let Some(e) = &c.expiry { println!("Expiry:   {:02}/{}", e.month, e.year); }
            println!("Kind:     {:?}", c.kind);
            c.number.clone()
        }
        ItemCore::Key(k) => {
            if let Some(l) = &k.label { println!("Label:    {l}"); }
            if let Some(a) = &k.algorithm { println!("Algo:     {a}"); }
            if let Some(pk) = &k.public_key { println!("Pubkey:   {pk}"); }
            Some(k.key_material.clone())
        }
        ItemCore::Document(d) => {
            println!("Filename: {}", d.filename);
            println!("MIME:     {}", d.mime_type);
            None
        }
        ItemCore::Totp(t) => {
            if let Some(i) = &t.issuer { println!("Issuer:   {i}"); }
            if let Some(l) = &t.label { println!("Label:    {l}"); }
            println!("Period:   {}s", t.config.period_seconds);
            println!("Digits:   {}", t.config.digits);
            None
        }
    };

    if let Some(secret) = primary_secret {
        if show {
            println!("Secret:   {}", secret.as_str());
        } else {
            println!("Secret:   ********  (use --show to reveal, --copy to clipboard)");
        }
        if copy {
            copy_to_clipboard_then_clear(&secret)?;
            eprintln!("Copied to clipboard (auto-clears in 30s).");
        }
    }

    Ok(())
}

fn copy_to_clipboard_then_clear(secret: &zeroize::Zeroizing<String>) -> Result<()> {
    use arboard::Clipboard;
    let mut cb = Clipboard::new().context("failed to access clipboard")?;
    cb.set_text(secret.as_str().to_string()).context("failed to write clipboard")?;
    let cleared_copy = zeroize::Zeroizing::new(secret.as_str().to_owned());
    // Unconditional clear (audit M6): spawn a detached thread that waits 30s
    // and then rewrites the clipboard with empty string. Even if the user
    // copies something else in the interim, we still overwrite once.
    std::thread::spawn(move || {
        std::thread::sleep(std::time::Duration::from_secs(30));
        if let Ok(mut cb) = Clipboard::new() {
            let _ = cb.set_text(String::new());
            drop(cleared_copy); // zeroize the detached copy
        }
    });
    Ok(())
}
