// 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 std::collections::HashMap;

use anyhow::Result;

use swh_graph::graph::*;
use swh_graph::labels::LabelNameId;
use swh_graph::swhid;
use swh_graph_stdlib::*;

use swh_graph_stdlib::fs::IdPath;

mod data;

#[test]
fn test_bitfield_id_path() {
    let ids = vec![LabelNameId(5), LabelNameId(3), LabelNameId(7)];

    let path = fs::BitFieldIdPath::from(ids.clone());
    assert_eq!(path.iter().collect::<Vec<_>>(), ids);

    let path = fs::BitFieldIdPath::from(ids.as_slice());
    assert_eq!(path.iter().collect::<Vec<_>>(), ids);

    let as_box: Box<[LabelNameId]> = path.into();
    assert_eq!(&*as_box, ids.as_slice());

    let path = fs::BitFieldIdPath::from(&[][..] as &[LabelNameId]);
    assert_eq!(path.iter().collect::<Vec<_>>(), vec![]);
}

#[test]
fn test_resolve_path() -> Result<()> {
    let graph = data::build_test_fs_tree_1()?;
    let props = graph.properties();
    let root_node = props.node_id(swhid!(swh:1:dir:0000000000000000000000000000000000000000))?;

    assert!(fs::resolve_name(&graph, root_node, "does-not-exist.txt").is_err());
    assert_eq!(
        props.swhid(fs::resolve_name(&graph, root_node, "README.md")?.unwrap()),
        swhid!(swh:1:cnt:0000000000000000000000000000000000000007)
    );
    assert_eq!(
        props.swhid(fs::resolve_name(&graph, root_node, "src")?.unwrap()),
        swhid!(swh:1:dir:0000000000000000000000000000000000000001)
    );

    assert!(fs::resolve_path(&graph, root_node, "does-not-exist.txt").is_err());
    assert!(fs::resolve_path(&graph, root_node, "README.md/is-not-a-dir").is_err());
    assert_eq!(
        props.swhid(fs::resolve_name(&graph, root_node, "doc")?.unwrap()),
        swhid!(swh:1:dir:0000000000000000000000000000000000000002)
    );
    assert_eq!(
        props.swhid(fs::resolve_path(&graph, root_node, "src/main.c")?.unwrap()),
        swhid!(swh:1:cnt:0000000000000000000000000000000000000004)
    );
    assert_eq!(
        props.swhid(fs::resolve_path(&graph, root_node, "doc/ls/ls.1")?.unwrap()),
        swhid!(swh:1:cnt:0000000000000000000000000000000000000006)
    );

    Ok(())
}

#[test]
fn test_resolve_path_by_id_with_bitfield() -> Result<()> {
    let graph = data::build_test_fs_tree_1()?;
    let props = graph.properties();
    let root_node = props.node_id(swhid!(swh:1:dir:0000000000000000000000000000000000000000))?;

    // Found: "src/main.c" → cnt:04
    let path = fs::BitFieldIdPath::from(vec![
        props.label_name_id(b"src")?,
        props.label_name_id(b"main.c")?,
    ]);
    assert_eq!(
        props.swhid(fs::resolve_path_by_id(&graph, root_node, path)?.unwrap()),
        swhid!(swh:1:cnt:0000000000000000000000000000000000000004)
    );

    // Not found: "main.c" is a known label but is not in the root dir
    let path = fs::BitFieldIdPath::from(vec![props.label_name_id(b"main.c")?]);
    assert_eq!(fs::resolve_path_by_id(&graph, root_node, path)?, None);

    Ok(())
}

#[test]
fn test_fs_ls_tree() -> Result<()> {
    let graph = data::build_test_fs_tree_1()?;
    let props = graph.properties();
    let doc_dir = props.node_id("swh:1:dir:0000000000000000000000000000000000000002")?;

    use swh_graph::labels::Permission;
    use swh_graph_stdlib::fs::FsTree::*;
    assert_eq!(
        fs::ls_tree(&graph, doc_dir)?,
        Directory(HashMap::from([(
            Vec::from("ls"),
            (
                Directory(HashMap::from([(
                    Vec::from("ls.1"),
                    (Content, Some(Permission::Content))
                )])),
                Some(Permission::Directory)
            )
        )]))
    );
    Ok(())
}
