# Copyright (C) 2025 Siemens
#
# SPDX-License-Identifier: MIT

import io
from pathlib import Path
import pytest
import xml.etree.ElementTree as ET

from debsbom.bomwriter.bomwriter import BomWriter
from debsbom.export.exporter import GraphExporter, GraphOutputFormat
from debsbom.sbom import SBOMType
from test_generation import sbom_generator


def test_export_format_from_str():
    assert GraphOutputFormat.from_str("graphml") == GraphOutputFormat.GRAPHML
    with pytest.raises(RuntimeError):
        GraphOutputFormat.from_str("foo")


@pytest.mark.parametrize("sbom_type", list(SBOMType))
def test_export_graphml(tmpdir, sbom_generator, sbom_type):
    match sbom_type:
        case SBOMType.SPDX:
            _spdx_tools = pytest.importorskip("spdx_tools")
        case SBOMType.CycloneDX:
            _cyclonedx = pytest.importorskip("cyclonedx")
        case _:
            assert False, "unreachable"

    NAMESPACE = "http://graphml.graphdrawing.org/xmlns"

    def get_name(node):
        for data in node.findall(f"{{{NAMESPACE}}}data"):
            if data.get("key") == "d_name":
                return data.text
        return None

    def get_essential(node):
        for data in node.findall(f"{{{NAMESPACE}}}data"):
            if data.get("key") == "d_essential":
                return data.text
        return None

    def get_arch(node):
        for data in node.findall(f"{{{NAMESPACE}}}data"):
            if data.get("key") == "d_arch":
                return data.text
        return None

    dbom = sbom_generator("tests/root/tree", sbom_types=[sbom_type])
    outdir = Path(tmpdir)
    dbom.generate(str(outdir / "sbom"), validate=False)

    exporter = GraphExporter.create(
        outdir / f"sbom.{sbom_type}.json", sbom_type, GraphOutputFormat.GRAPHML
    )
    buffer = io.BytesIO()
    with io.TextIOWrapper(buffer) as wrapper:
        exporter.export(wrapper)
        wrapper.flush()
        wrapper.seek(0)
        tree = ET.parse(wrapper)

    root = tree.getroot()
    assert root.tag == f"{{{NAMESPACE}}}graphml"
    node_tag = f"{{{NAMESPACE}}}node"
    assert any(map(lambda n: get_name(n) == "binutils", root.iter(node_tag)))
    if sbom_type == SBOMType.CycloneDX:
        jansson = next(filter(lambda n: get_name(n) == "libjansson4", root.iter(node_tag)))
        assert get_essential(jansson) == "no"

    binutils = next(
        filter(lambda n: get_name(n) == "binutils-x86-64-linux-gnu", root.iter(node_tag))
    )
    assert get_arch(binutils) == "amd64"
    binutils_src = next(
        filter(
            lambda n: get_arch(n) == "source" and get_name(n) == "binutils", root.iter(node_tag)
        ),
        None,
    )
    assert binutils_src is not None

    edge_tag = f"{{{NAMESPACE}}}edge"
    assert any(map(lambda n: "binutils" in n.get("id"), root.iter(edge_tag)))
