mod common;
use common::TestVault;

const FIXTURE: &str = "tests/fixtures/lastpass-sample.csv";

fn fixture_path() -> std::path::PathBuf {
    // Manifest dir = crates/relicario-cli; the fixture is relative to it.
    std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(FIXTURE)
}

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

    let out = v.run(&["import", "lastpass", fixture_path().to_str().unwrap()]);
    assert!(
        out.status.success(),
        "import failed:\nstdout: {}\nstderr: {}",
        String::from_utf8_lossy(&out.stdout),
        String::from_utf8_lossy(&out.stderr),
    );

    let stderr = String::from_utf8(out.stderr).unwrap();
    // 9 items expected (see fixture comment).
    assert!(stderr.contains("Imported 9"), "stderr: {stderr}");
    assert!(stderr.contains("skipped 2"), "stderr: {stderr}");

    // Each warning surfaces.
    assert!(stderr.contains("invalid base32 TOTP"), "TOTP warning missing");
    assert!(stderr.contains("invalid URL"),         "URL warning missing");
    assert!(stderr.contains("missing `name`"),      "name-missing warning missing");
    assert!(stderr.contains("missing `password`"),  "password-missing warning missing");
}

#[test]
fn list_after_import_shows_imported_titles() {
    let v = TestVault::init();
    v.run(&["import", "lastpass", fixture_path().to_str().unwrap()]);

    let out = v.run(&["list"]);
    let stdout = String::from_utf8(out.stdout).unwrap();
    assert!(stdout.contains("GitHub"));
    assert!(stdout.contains("Gmail"));
    assert!(stdout.contains("Home Wifi"));
    assert!(stdout.contains("Visa Card"));
    assert!(stdout.contains("日本語サイト"));
    // Skipped rows must NOT appear.
    assert!(!stdout.contains("No Password"),
        "row with no password should have been skipped");
}

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

    // Count commits before.
    let before = std::process::Command::new("git")
        .arg("-C").arg(v.path())
        .args(["rev-list", "--count", "HEAD"])
        .output().unwrap();
    let before_n: u32 = String::from_utf8(before.stdout).unwrap().trim().parse().unwrap();

    v.run(&["import", "lastpass", fixture_path().to_str().unwrap()]);

    let after = std::process::Command::new("git")
        .arg("-C").arg(v.path())
        .args(["rev-list", "--count", "HEAD"])
        .output().unwrap();
    let after_n: u32 = String::from_utf8(after.stdout).unwrap().trim().parse().unwrap();

    assert_eq!(after_n, before_n + 1, "expected exactly one new commit");

    // Commit message includes the count + "LastPass".
    let log = std::process::Command::new("git")
        .arg("-C").arg(v.path())
        .args(["log", "-1", "--pretty=%s"])
        .output().unwrap();
    let subject = String::from_utf8(log.stdout).unwrap();
    assert!(subject.contains("9 items"));
    assert!(subject.contains("LastPass"));
}

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

    // Header-only CSV with one bad row → 0 items.
    let bad_csv = v.path().join("empty.csv");
    std::fs::write(
        &bad_csv,
        "url,username,password,totp,extra,name,grouping,fav\n,,,,,,,\n",
    ).unwrap();

    let out = v.run(&["import", "lastpass", bad_csv.to_str().unwrap()]);
    assert!(!out.status.success(), "expected non-zero exit on zero items");
    let stderr = String::from_utf8(out.stderr).unwrap();
    assert!(stderr.contains("imported 0 items"), "stderr: {stderr}");
}

#[test]
fn import_rejects_unrecognized_header() {
    let v = TestVault::init();
    let bad_csv = v.path().join("wrong.csv");
    std::fs::write(&bad_csv, "name,url,user,pass\nA,https://x,u,p\n").unwrap();

    let out = v.run(&["import", "lastpass", bad_csv.to_str().unwrap()]);
    assert!(!out.status.success());
    let stderr = String::from_utf8(out.stderr).unwrap();
    assert!(
        stderr.contains("LastPass") || stderr.contains("expected"),
        "stderr: {stderr}",
    );
}

#[test]
fn imported_items_keep_unique_ids_across_runs() {
    // Decision D12: two imports of the same CSV must not collide.
    let v = TestVault::init();
    v.run(&["import", "lastpass", fixture_path().to_str().unwrap()]);
    v.run(&["import", "lastpass", fixture_path().to_str().unwrap()]);

    let out = v.run(&["list"]);
    let stdout = String::from_utf8(out.stdout).unwrap();
    // Each title imported twice — count occurrences of "GitHub" must be 2.
    let github_count = stdout.matches("GitHub").count();
    assert_eq!(github_count, 2, "stdout: {stdout}");
}
