//! Common helpers shared by all commands.

use std::io::{self, Write};
use std::path::PathBuf;
use std::time::{SystemTime, UNIX_EPOCH};

use anyhow::{anyhow, Context, Result};

use levcs_core::Repository;
use levcs_identity::keychain::Keychain;
use levcs_identity::keys::SecretKey;

pub fn now_micros() -> i64 {
    SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .map(|d| d.as_micros() as i64)
        .unwrap_or(0)
}

pub fn open_repo() -> Result<Repository> {
    let cwd = std::env::current_dir()?;
    Ok(Repository::discover(&cwd)?)
}

pub fn keychain_path() -> PathBuf {
    Keychain::default_path()
}

pub fn load_keychain() -> Result<Keychain> {
    Ok(Keychain::load_or_default(&keychain_path())?)
}

pub fn save_keychain(kc: &Keychain) -> Result<()> {
    Ok(kc.save(&keychain_path())?)
}

pub fn read_passphrase(prompt: &str) -> Result<String> {
    eprint!("{prompt}");
    io::stderr().flush().ok();
    // Best-effort no-echo: rely on terminal raw mode if available; otherwise
    // fall back to plain readline. This is intentionally simple to avoid
    // pulling another crate; users on headless CI should pass keys via
    // unencrypted slots or a future agent.
    let mut buf = String::new();
    io::stdin().read_line(&mut buf)?;
    if buf.ends_with('\n') {
        buf.pop();
        if buf.ends_with('\r') {
            buf.pop();
        }
    }
    Ok(buf)
}

/// Resolve a key label and load the secret. If `label` is None, default to
/// `"personal"`, then to the only key in the chain if there is exactly one.
pub fn load_secret(label: Option<&str>) -> Result<(String, SecretKey)> {
    let kc = load_keychain()?;
    let chosen = match label {
        Some(l) => l.to_string(),
        None => {
            if kc.entry("personal").is_some() {
                "personal".into()
            } else if kc.keys.len() == 1 {
                kc.keys[0].label.clone()
            } else if kc.keys.is_empty() {
                return Err(anyhow!(
                    "no keys in keychain at {:?}; run `levcs key generate <label>`",
                    keychain_path()
                ));
            } else {
                return Err(anyhow!("multiple keys in keychain; pass --key <label>"));
            }
        }
    };
    let entry = kc
        .entry(&chosen)
        .ok_or_else(|| anyhow!("unknown key label: {chosen}"))?
        .clone();
    let sk = if entry.private.is_some() {
        kc.secret(&chosen, || Ok(String::new()))
            .context("loading plaintext secret")?
    } else {
        let pp = read_passphrase(&format!("passphrase for key '{chosen}': "))?;
        kc.secret(&chosen, || Ok(pp.clone()))
            .context("decrypting secret")?
    };
    Ok((chosen, sk))
}
