from sentra.graph import build_evidence_graph
from sentra.models import CertificateFinding, Device, Finding, FirmwareArtifact, NetworkScanArtifact, Service, ServiceHint, VulnerabilityMatch


def test_build_evidence_graph_creates_device_and_service_nodes() -> None:
    artifact = NetworkScanArtifact(
        target="192.168.1.0/24",
        devices=[
            Device(
                host="cam-01",
                ip_address="192.168.1.10",
                protocols=["web", "rtsp"],
                services=[
                    Service(port=80, protocol="tcp", service="http", banner="Boa/0.94"),
                    Service(port=554, protocol="tcp", service="rtsp", banner="RTSP"),
                ],
                findings=[
                    Finding(
                        title="Exposed admin panel",
                        severity="high",
                        confidence=0.9,
                        description="HTTP admin interface is reachable.",
                    )
                ],
            )
        ],
    )

    correlation = build_evidence_graph(artifact, None)

    assert correlation.summary["devices"] == 1
    assert correlation.summary["services"] == 2
    assert correlation.summary["protocols"] >= 2

    node_ids = {node.id for node in correlation.nodes}
    assert "device:192.168.1.10" in node_ids
    assert "service:192.168.1.10:tcp:80" in node_ids
    assert "service:192.168.1.10:tcp:554" in node_ids

    relations = {(edge.source, edge.target, edge.relation) for edge in correlation.edges}
    assert ("device:192.168.1.10", "service:192.168.1.10:tcp:80", "exposes") in relations
    assert ("service:192.168.1.10:tcp:80", "protocol:tcp", "uses_protocol") in relations


def test_build_evidence_graph_correlates_firmware_analysis_nodes() -> None:
    firmware = FirmwareArtifact(
        path="firmware.zip",
        sha256="b" * 64,
        size_bytes=512,
        suspected_vendors=["Acme Vision"],
        service_hints=[ServiceHint(service="http", source_path="www/index.html", rationale="matched", confidence=0.8)],
        certificate_findings=[
            CertificateFinding(
                path="certs/device.pem",
                common_name="device.local",
                confidence=0.83,
                rationale="embedded certificate",
            )
        ],
        config_hints=[],
        vulnerability_matches=[
            VulnerabilityMatch(
                cve_id="CVE-2026-1234",
                product="nginx",
                normalized_product="nginx",
                category="probable-match",
                severity="high",
                summary="test",
                confidence=0.81,
                rationale="nginx matched as probable-match based on product evidence.",
            )
        ],
        findings=[
            Finding(
                title="Embedded certificate material",
                severity="medium",
                confidence=0.7,
                description="Certificate embedded.",
            )
        ],
    )
    network = NetworkScanArtifact(
        target="t",
        devices=[Device(host="cam-01", ip_address="192.168.1.10", vendor="Acme Vision", services=[Service(port=80, protocol="tcp", service="http")])],
    )

    correlation = build_evidence_graph(network, firmware)

    assert correlation.summary["firmware"] == 1
    assert correlation.summary["findings"] >= 1
    assert correlation.summary["certificates"] >= 1
    assert "correlated_firmware_signals" in correlation.insights
    assert correlation.insights["vulnerability_categories"]["probable-match"] >= 1
    assert correlation.insights["ranked_weak_paths"]
    relations = {(edge.source, edge.target, edge.relation) for edge in correlation.edges}
    assert ("device:192.168.1.10", "firmware:bbbbbbbbbbbb", "likely_runs") in relations
    assert ("device:192.168.1.10", "service-hint:http:www/index.html", "matches_firmware_signal") in relations

