//! `relicario init` — bootstrap a fresh vault in the current directory.

use std::path::PathBuf;

use anyhow::{Context, Result};

pub fn cmd_init(image: PathBuf, output: PathBuf) -> Result<()> {
    use std::fs;
    use rand::{rngs::OsRng, RngCore};
    use relicario_core::{
        derive_master_key, encrypt_manifest, encrypt_settings, imgsecret,
        validate_passphrase_strength, KdfParams, Manifest, VaultSettings,
    };
    use zeroize::Zeroizing;

    let root = std::env::current_dir()?;
    let relicario_dir = root.join(".relicario");
    if relicario_dir.exists() {
        anyhow::bail!(".relicario/ already exists in {}", root.display());
    }

    // Passphrase with strength gate (audit H3).
    // RELICARIO_TEST_PASSPHRASE is a test-only escape hatch that bypasses the
    // TTY prompt so integration tests can run without a real TTY.
    let passphrase = if let Some(p) = crate::test_passphrase_override() {
        Zeroizing::new(p)
    } else {
        Zeroizing::new(rpassword::prompt_password("Choose a passphrase: ")?)
    };
    let confirm = if crate::test_passphrase_override().is_some() {
        passphrase.clone()
    } else {
        Zeroizing::new(rpassword::prompt_password("Confirm passphrase: ")?)
    };
    if passphrase.as_str() != confirm.as_str() {
        anyhow::bail!("passphrases do not match");
    }
    if let Err(e) = validate_passphrase_strength(&passphrase) {
        anyhow::bail!("{}. Choose a longer or more entropic phrase.", e);
    }

    // Image secret: 32 random bytes, embedded in the carrier.
    let image_secret = {
        let mut buf = Zeroizing::new([0u8; 32]);
        OsRng.fill_bytes(buf.as_mut_slice());
        buf
    };
    let carrier = fs::read(&image)
        .with_context(|| format!("failed to read carrier image {}", image.display()))?;
    let stego = imgsecret::embed(&carrier, &image_secret)?;
    fs::write(&output, &stego)
        .with_context(|| format!("failed to write reference image {}", output.display()))?;

    // Vault salt + KDF params.
    let mut salt = [0u8; 32];
    OsRng.fill_bytes(&mut salt);
    let params = KdfParams { argon2_m: 65536, argon2_t: 3, argon2_p: 4 };

    // Derive master key, then persist an empty Manifest + default VaultSettings.
    let master_key = derive_master_key(passphrase.as_bytes(), &image_secret, &salt, &params)?;

    fs::create_dir_all(&relicario_dir)?;
    fs::create_dir_all(root.join("items"))?;
    fs::create_dir_all(root.join("attachments"))?;
    fs::write(relicario_dir.join("salt"), salt)?;
    fs::write(
        relicario_dir.join("params.json"),
        serde_json::to_string_pretty(&crate::session::ParamsFile::for_new_vault(&params))?,
    )?;
    let manifest = Manifest::new();
    fs::write(root.join("manifest.enc"), encrypt_manifest(&manifest, &master_key)?)?;
    let settings = VaultSettings::default();
    fs::write(root.join("settings.enc"), encrypt_settings(&settings, &master_key)?)?;

    // .gitignore excludes the reference image.
    let fname = output.file_name()
        .ok_or_else(|| anyhow::anyhow!("output path has no filename: {}", output.display()))?
        .to_string_lossy();
    let gitignore = format!("{fname}\n");
    fs::write(root.join(".gitignore"), gitignore)?;

    // git init + initial commit via hardened wrapper.
    crate::helpers::git_run(&root, &["init"], "init: git init")?;
    let _ = crate::helpers::git_command(&root, &[
        "add", ".gitignore", ".relicario/params.json",
        ".relicario/salt", "manifest.enc", "settings.enc",
    ]).status()?;
    crate::helpers::git_run(
        &root,
        &["commit", "-m", "init: new Relicario vault (format v2)"],
        "init: git commit",
    )?;

    eprintln!("Vault initialized at {}", root.display());
    eprintln!("Reference image: {}", output.display());
    eprintln!("  \u{2192} back this file up somewhere safe; it is your second factor.");
    Ok(())
}
