package com.blackduck.integration.detectable.detectables.cargo.functional;

import java.io.IOException;
import java.nio.file.Paths;

import com.blackduck.integration.detectable.detectables.cargo.CargoDependencyType;
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.Assertions;

import com.blackduck.integration.bdio.model.Forge;
import com.blackduck.integration.detectable.Detectable;
import com.blackduck.integration.detectable.DetectableEnvironment;
import com.blackduck.integration.detectable.detectables.cargo.CargoDetectableOptions;
import com.blackduck.integration.detectable.extraction.Extraction;
import com.blackduck.integration.detectable.functional.DetectableFunctionalTest;
import com.blackduck.integration.detectable.util.graph.NameVersionGraphAssert;
import com.blackduck.integration.detectable.detectable.util.EnumListFilter;

public class CargoLockDependencyExclusionTest extends DetectableFunctionalTest {

    public CargoLockDependencyExclusionTest() throws IOException {
        super("cargo-lock");
    }

    @Override
    protected void setup() throws IOException {
        addFile(
            Paths.get("Cargo.toml"),
            "[package]",
            "name = \"sample-cargo-project\"",
            "version = \"0.1.0\"",
            "edition = \"2024\"",
            "build = \"build.rs\"",
            "",
            "[dependencies]",
            "rand = \"0.9.1\"",
            "time = \"0.3.41\"",
            "",
            "[build-dependencies]",
            "regex = \"1.0.1\"",
            "",
            "[dev-dependencies]",
            "openssl = \"0.10.73\""
        );

        addFile(
            Paths.get("Cargo.lock"),
            "# This file is automatically @generated by Cargo.",
            "# It is not intended for manual editing.",
            "version = 4",
            "",
            "[[package]]",
            "name = \"rand\"",
            "version = \"0.9.1\"",
            "dependencies = [",
            " \"rand_core\",",
            "]",
            "",
            "[[package]]",
            "name = \"time\"",
            "version = \"0.3.41\"",
            "",
            "[[package]]",
            "name = \"regex\"",
            "version = \"1.0.1\"",
            "dependencies = [",
            " \"aho-corasick\",",
            "]",
            "",
            "[[package]]",
            "name = \"openssl\"",
            "version = \"0.10.73\"",
            "dependencies = [",
            " \"bitflags\",",
            "]",
            "",
            "[[package]]",
            "name = \"rand_core\"",
            "version = \"0.9.3\"",
            "",
            "[[package]]",
            "name = \"aho-corasick\"",
            "version = \"1.1.3\"",
            "",
            "[[package]]",
            "name = \"bitflags\"",
            "version = \"2.9.1\""
        );
    }

    @NotNull
    @Override
    public Detectable create(@NotNull DetectableEnvironment detectableEnvironment) {
        return detectableFactory.createCargoLockfileDetectable(
            detectableEnvironment,
            new CargoDetectableOptions(EnumListFilter.fromExcluded(CargoDependencyType.NORMAL))
        );
    }

    @Override
    public void assertExtraction(@NotNull Extraction extraction) {
        Assertions.assertEquals(1, extraction.getCodeLocations().size());

        NameVersionGraphAssert graphAssert = new NameVersionGraphAssert(Forge.CRATES, extraction.getCodeLocations().get(0).getDependencyGraph());

        // Verify direct dependencies from [build-dependencies] and [dev-dependencies]
        graphAssert.hasRootDependency("regex", "1.0.1");
        graphAssert.hasRootDependency("openssl", "0.10.73");

        // Verify transitive dependencies of [build-dependencies]
        graphAssert.hasParentChildRelationship("regex", "1.0.1", "aho-corasick", "1.1.3");

        // Verify transitive dependencies of [dev-dependencies]
        graphAssert.hasParentChildRelationship("openssl", "0.10.73", "bitflags", "2.9.1");

        // Ensure [dependencies] and their transitives are excluded
        graphAssert.hasNoDependency("rand", "0.9.1");
        graphAssert.hasNoDependency("rand_core", "0.9.3");
        graphAssert.hasNoDependency("time", "0.3.41");
    }
}