// Copyright (C) 2024-2026  The Software Heritage developers
// See the AUTHORS file at the top-level directory of this distribution
// License: GNU General Public License version 3, or any later version
// See top-level LICENSE file for more information

use anyhow::Result;

use swh_graph::graph::*;
use swh_graph::graph_builder::GraphBuilder;
use swh_graph::labels::{Permission, Visit, VisitStatus, VisitType};
use swh_graph::swhid;
use swh_graph_stdlib::*;

mod data;

#[test]
#[cfg_attr(miri, ignore)] // miri does not support file-backed mmap
fn test_find_root_dir() -> Result<()> {
    let mut builder = GraphBuilder::default();
    let rev0 = builder
        .node(swhid!(swh:1:rev:0000000000000000000000000000000000000000))?
        .done();
    let rev1 = builder
        .node(swhid!(swh:1:rev:0000000000000000000000000000000000000001))?
        .done();
    let dir2 = builder
        .node(swhid!(swh:1:dir:0000000000000000000000000000000000000002))?
        .done();
    let dir3 = builder
        .node(swhid!(swh:1:dir:0000000000000000000000000000000000000003))?
        .done();
    builder.arc(rev1, rev0);
    builder.arc(rev0, dir2);
    builder.arc(rev1, dir3);
    builder.dir_arc(dir3, dir2, Permission::Directory, "subdir");
    let graph = builder.done()?;

    assert_eq!(find_root_dir(&graph, rev0)?.unwrap(), dir2);
    assert_eq!(find_root_dir(&graph, rev1)?.unwrap(), dir3);

    Ok(())
}

#[test]
fn test_find_latest_snp() -> Result<()> {
    let mut builder = GraphBuilder::default();
    let ori0 = builder
        .node(swhid!(swh:1:ori:0000000000000000000000000000000000000000))?
        .done();
    let snp1 = builder
        .node(swhid!(swh:1:snp:0000000000000000000000000000000000000001))?
        .done();
    let snp2 = builder
        .node(swhid!(swh:1:snp:0000000000000000000000000000000000000002))?
        .done();
    let snp3 = builder
        .node(swhid!(swh:1:snp:0000000000000000000000000000000000000003))?
        .done();
    let visit1 = Visit::new(VisitStatus::Full, 1719568024, VisitType::Unknown).unwrap();
    let visit2 = Visit::new(VisitStatus::Full, 1719578024, VisitType::Unknown).unwrap();
    let visit3 = Visit::new(VisitStatus::Partial, 1719588024, VisitType::Unknown).unwrap();
    builder.ori_arc(
        ori0,
        snp1,
        visit1.status(),
        visit1.timestamp(),
        visit1.visit_type(),
    );
    builder.ori_arc(
        ori0,
        snp2,
        visit2.status(),
        visit2.timestamp(),
        visit2.visit_type(),
    );
    builder.ori_arc(
        ori0,
        snp3,
        visit3.status(),
        visit3.timestamp(),
        visit3.visit_type(),
    );
    let graph = builder.done()?;

    assert_eq!(
        find_latest_snp(&graph, ori0)?,
        Some((snp2, visit2.timestamp()))
    );
    Ok(())
}

#[test]
fn test_iter_nodes() -> Result<()> {
    let graph = data::build_test_graph_1()?;
    let props = graph.properties();
    let ori1 = props.node_id(swhid!(swh:1:ori:83404f995118bd25774f4ac14422a8f175e7a054))?;
    let ori2 = props.node_id(swhid!(swh:1:ori:8f50d3f60eae370ddbf85c86219c55108a350165))?;

    assert_eq!(iter_nodes(&graph, [ori1]).count(), 12);
    assert_eq!(iter_nodes(&graph, [ori2]).count(), 21);

    Ok(())
}

#[test]
#[allow(clippy::needless_borrows_for_generic_args)]
fn test_iter_nodes_backward_compat() -> Result<()> {
    let graph = data::build_test_graph_1()?;
    let props = graph.properties();
    let ori1 = props.node_id(swhid!(swh:1:ori:83404f995118bd25774f4ac14422a8f175e7a054))?;
    let ori2 = props.node_id(swhid!(swh:1:ori:8f50d3f60eae370ddbf85c86219c55108a350165))?;

    assert_eq!(iter_nodes(&graph, &[ori1]).count(), 12);
    assert_eq!(iter_nodes(&graph, &[ori2]).count(), 21);

    Ok(())
}
