mod common;
use common::Environment;
use common::Result;

fn create_environment() -> Result<(Environment, String)> {
    Environment::scooby_gang_bootstrap()
}

#[test]
#[allow(unused)]
fn git_refs() -> anyhow::Result<()> {
    // The commits:
    //
    // commit-2-1      commit-3-1
    //    |  good         |  good
    // commit-2-0      commit-3-0
    //    bad   \    /   good
    //          commit-2
    //             | good
    //          commit-1
    //             | good
    //          commit-0

    let (e, commit_0) = create_environment()?;
    let p = e.git_state();

    e.git(&["branch", "commit-0"])?;

    let commit_1
        = e.git_commit(&[("a", Some(b"1"))], "1", Some(&e.willow)).unwrap();
    e.git(&["branch", "commit-1"])?;
    assert!(e.sq_git(&["log", "--trust-root", &commit_0]).is_ok());

    let commit_2
        = e.git_commit(&[("a", Some(b"2"))], "2", Some(&e.willow)).unwrap();
    e.git(&["branch", "commit-2"])?;
    assert!(e.sq_git(&["log", "--trust-root", &commit_0]).is_ok());

    // The bad commit.
    let commit_2_0
        = e.git_commit(&[("a", Some(b"2-0"))], "2-0", Some(&e.xander)).unwrap();
    e.git(&["branch", "commit-2-0"])?;
    assert!(e.sq_git(&["log", "--trust-root", &commit_0]).is_err());

    let commit_2_1
        = e.git_commit(&[("a", Some(b"2-1"))], "2-1", Some(&e.willow)).unwrap();
    e.git(&["branch", "commit-2-1"])?;
    assert!(e.sq_git(&["log", "--trust-root", &commit_0]).is_err());

    // Move back to commit-2.
    e.git(&["checkout", "commit-2"])?;
    e.git(&["clean", "-fdx"])?;
    assert!(e.sq_git(&["log", "--trust-root", &commit_0]).is_ok());

    let commit_3_0
        = e.git_commit(&[("a", Some(b"3-0"))], "3-0", Some(&e.willow)).unwrap();
    e.git(&["branch", "commit-3-0"])?;
    assert!(e.sq_git(&["log", "--trust-root", &commit_0]).is_ok());

    let commit_3_1
        = e.git_commit(&[("a", Some(b"3-1"))], "3-1", Some(&e.willow)).unwrap();
    e.git(&["branch", "commit-3-1"])?;
    assert!(e.sq_git(&["log", "--trust-root", &commit_0]).is_ok());

    // Debugging.
    let output = e.git(
        &["log", "--pretty=oneline", "--graph", "commit-2-1", "commit-3-1"])
        .unwrap();
    eprintln!("{}", String::from_utf8_lossy(&output.stdout));

    assert!(e.git(&["tag", "v1", "commit-1"]).is_ok());
    assert!(e.git(&["tag", "v2", "commit-2"]).is_ok());
    assert!(e.git(&["tag", "v2.1", "commit-2-1"]).is_ok());

    let paths = &[
        // Trust root / commit to check / ok / ok with trust root's parent.
        (&commit_1[..], "commit-1", &commit_2[..], "commit-2", true, true),
        (&commit_1[..], "commit-1", &commit_3_1[..], "commit-3-0", true, true),
        (&commit_1[..], "commit-1", &commit_3_1[..], "commit-3-1", true, true),
        (&commit_1[..], "commit-1", &commit_2_1[..], "commit-2-1", false, false),
        (&commit_2_0[..], "commit-2-0", &commit_2_1[..], "commit-2-1", true, false),
        // Use tags instead of branches.
        (&commit_1[..], "v1", &commit_2[..], "v2", true, true),
        (&commit_1[..], "v1", &commit_2_1[..], "v2.1", false, false),
    ];

    for (trust_root_hash, trust_root, commit_hash, commit, good, p_good)
        in paths.iter()
    {
        eprintln!("Testing: {} ({}) .. {} ({}) ({}, {})",
                  trust_root_hash, trust_root,
                  commit_hash, commit,
                  good, p_good);

        // Commit id.
        assert_eq!(
            e.sq_git(&["log",
                       "--trust-root", trust_root_hash,
                       commit_hash])
                .is_ok(),
            *good);

        // Short commit id.
        assert_eq!(
            e.sq_git(&["log",
                       "--trust-root", &trust_root_hash[0..7],
                       &commit_hash[..]])
                .is_ok(),
            *good);

        // Using branches.
        assert_eq!(
            e.sq_git(&["log",
                       "--trust-root", trust_root,
                       commit])
                .is_ok(),
            *good);

        // Trust root's parent.
        assert_eq!(
            e.sq_git(&["log",
                       "--trust-root", &format!("{}^", trust_root_hash),
                       commit_hash])
                .is_ok(),
            *p_good);

        // Trust root's parent, with branches
        assert_eq!(
            e.sq_git(&["log",
                       "--trust-root", &format!("{}^", trust_root),
                       commit])
                .is_ok(),
            *p_good);

        // Make sure we can use the configuration file to set a trust
        // root.
        assert!(e.git(&["config", "sequoia.trustRoot", trust_root_hash]).is_ok());
        assert_eq!(
            e.sq_git(&["log", commit_hash])
                .is_ok(),
            *good);

        assert!(e.git(&["config", "sequoia.trustRoot", trust_root]).is_ok());
        assert_eq!(
            e.sq_git(&["log", commit_hash])
                .is_ok(),
            *good);
    }

    Ok(())
}
