mod common;
use common::TestVault;
use std::process::Command;
use assert_cmd::cargo::CommandCargoExt;

const BACKUP_PASS: &str = "strong-backup-pass-test-2026";

#[test]
fn export_then_restore_round_trip() {
    let v = TestVault::init();

    v.run(&["add", "login", "--title", "GitHub", "--username", "alice", "--password", "p"]);
    v.run(&["add", "login", "--title", "Email", "--username", "bob", "--password", "q"]);

    let backup_path = v.path().join("vault.relbak");
    let out = v.run_with_backup_pass(
        &["backup", "export", backup_path.to_str().unwrap()],
        BACKUP_PASS,
    );
    assert!(out.status.success(), "export failed: {:?}", String::from_utf8_lossy(&out.stderr));
    assert!(backup_path.exists());
    assert!(v.path().join(".relicario/last_backup").exists());

    // Restore into a fresh dir.
    let restore_dir = tempfile::TempDir::new().unwrap();
    let out = Command::cargo_bin("relicario")
        .unwrap()
        .current_dir(restore_dir.path())
        .env("RELICARIO_TEST_BACKUP_PASSPHRASE", BACKUP_PASS)
        .args(["backup", "restore", backup_path.to_str().unwrap(), "."])
        .output()
        .unwrap();
    assert!(out.status.success(), "restore failed: {:?}", String::from_utf8_lossy(&out.stderr));

    // Vault should be unlockable in the restore dir using the same passphrase + image.
    // Since the original vault didn't include the image, we copy it in manually
    // (the standard restore-without-image flow expects the user to keep their
    // reference image separately).
    std::fs::copy(&v.reference_image, restore_dir.path().join("reference.jpg")).unwrap();

    let out = Command::cargo_bin("relicario")
        .unwrap()
        .current_dir(restore_dir.path())
        .env("RELICARIO_TEST_PASSPHRASE", &v.passphrase)
        .env("RELICARIO_IMAGE", restore_dir.path().join("reference.jpg"))
        .args(["list"])
        .output()
        .unwrap();
    let stdout = String::from_utf8(out.stdout).unwrap();
    assert!(stdout.contains("GitHub"));
    assert!(stdout.contains("Email"));
}

#[test]
fn restore_refuses_non_empty_target() {
    let v = TestVault::init();
    let backup_path = v.path().join("vault.relbak");
    v.run_with_backup_pass(&["backup", "export", backup_path.to_str().unwrap()], BACKUP_PASS);

    let out = Command::cargo_bin("relicario")
        .unwrap()
        .current_dir(v.path())   // already has a .relicario/
        .env("RELICARIO_TEST_BACKUP_PASSPHRASE", BACKUP_PASS)
        .args(["backup", "restore", backup_path.to_str().unwrap(), "."])
        .output()
        .unwrap();
    assert!(!out.status.success());
    let err = String::from_utf8(out.stderr).unwrap();
    assert!(err.contains("already contains a Relicario vault"), "stderr: {err}");
}

#[test]
fn export_with_include_image_round_trips_the_image() {
    let v = TestVault::init();
    let backup_path = v.path().join("vault.relbak");
    v.run_with_backup_pass(
        &["backup", "export", backup_path.to_str().unwrap(), "--include-image"],
        BACKUP_PASS,
    );

    let restore_dir = tempfile::TempDir::new().unwrap();
    let out = Command::cargo_bin("relicario")
        .unwrap()
        .current_dir(restore_dir.path())
        .env("RELICARIO_TEST_BACKUP_PASSPHRASE", BACKUP_PASS)
        .args(["backup", "restore", backup_path.to_str().unwrap(), "."])
        .output()
        .unwrap();
    assert!(out.status.success(), "{:?}", String::from_utf8_lossy(&out.stderr));
    assert!(restore_dir.path().join("reference.jpg").exists(),
        "image should be restored when --include-image was used");
}

#[test]
fn export_with_no_history_skips_git_dir() {
    let v = TestVault::init();
    let backup_path = v.path().join("vault.relbak");
    v.run_with_backup_pass(
        &["backup", "export", backup_path.to_str().unwrap(), "--no-history"],
        BACKUP_PASS,
    );

    let restore_dir = tempfile::TempDir::new().unwrap();
    let out = Command::cargo_bin("relicario")
        .unwrap()
        .current_dir(restore_dir.path())
        .env("RELICARIO_TEST_BACKUP_PASSPHRASE", BACKUP_PASS)
        .args(["backup", "restore", backup_path.to_str().unwrap(), "."])
        .output()
        .unwrap();
    assert!(out.status.success(), "{:?}", String::from_utf8_lossy(&out.stderr));

    // .git/ should exist but contain only the "restore from backup ..." commit.
    assert!(restore_dir.path().join(".git").is_dir());
    let out = std::process::Command::new("git")
        .current_dir(restore_dir.path())
        .args(["log", "--oneline"])
        .output()
        .unwrap();
    let log = String::from_utf8(out.stdout).unwrap();
    assert_eq!(log.lines().count(), 1, "expected one commit, got: {log}");
    assert!(log.contains("restore from backup"));
}

#[test]
fn wrong_backup_passphrase_fails() {
    let v = TestVault::init();
    let backup_path = v.path().join("vault.relbak");
    v.run_with_backup_pass(&["backup", "export", backup_path.to_str().unwrap()], BACKUP_PASS);

    let restore_dir = tempfile::TempDir::new().unwrap();
    let out = Command::cargo_bin("relicario")
        .unwrap()
        .current_dir(restore_dir.path())
        .env("RELICARIO_TEST_BACKUP_PASSPHRASE", "definitely-wrong")
        .args(["backup", "restore", backup_path.to_str().unwrap(), "."])
        .output()
        .unwrap();
    assert!(!out.status.success());
    let err = String::from_utf8(out.stderr).unwrap();
    assert!(err.contains("wrong backup passphrase"), "stderr: {err}");
}
