///|
pub fn compare_factory_topologies(
  base_graph : @graph.FactoryGraph,
  target_graph : @graph.FactoryGraph,
) -> TopologyDiffReport {
  let added_nodes = []
  let removed_nodes = []
  let modified_nodes = []
  let breaking_changes = []
  let recommendations = []

  let base_nodes = base_graph.get_all_nodes()
  let target_nodes = target_graph.get_all_nodes()

  // Check removed and modified nodes
  for base_n in base_nodes {
    let nid = base_n.id()
    match target_graph.get_node(nid) {
      None => {
        removed_nodes.push(nid)
        if base_n.node_type() == @types.NodeType::PowerSource ||
          base_n.node_type() == @types.NodeType::PLCController {
          breaking_changes.push(
            "Removed core plant infrastructure node: " + nid,
          )
        }
      }
      Some(tgt_n) => {
        let prop_changes = []
        if base_n.cycle_time_sec() != tgt_n.cycle_time_sec() {
          let ct_increased = tgt_n.cycle_time_sec() > base_n.cycle_time_sec()
          prop_changes.push({
            field_name: "cycle_time_sec",
            old_value: base_n.cycle_time_sec().to_string(),
            new_value: tgt_n.cycle_time_sec().to_string(),
            is_breaking: ct_increased,
          })
          if ct_increased {
            recommendations.push(
              "Node " +
              nid +
              " cycle time increased from " +
              base_n.cycle_time_sec().to_string() +
              "s to " +
              tgt_n.cycle_time_sec().to_string() +
              "s; check takt time impact.",
            )
          }
        }

        if base_n.nominal_power_kw() != tgt_n.nominal_power_kw() {
          prop_changes.push({
            field_name: "nominal_power_kw",
            old_value: base_n.nominal_power_kw().to_string(),
            new_value: tgt_n.nominal_power_kw().to_string(),
            is_breaking: false,
          })
        }

        if base_n.safety_zone_id() != tgt_n.safety_zone_id() {
          prop_changes.push({
            field_name: "safety_zone_id",
            old_value: base_n.safety_zone_id(),
            new_value: tgt_n.safety_zone_id(),
            is_breaking: true,
          })
          breaking_changes.push(
            "Node " +
            nid +
            " safety domain reassigned from " +
            base_n.safety_zone_id() +
            " to " +
            tgt_n.safety_zone_id(),
          )
        }

        if prop_changes.length() > 0 {
          modified_nodes.push({
            node_id: nid,
            diff_type: NodeDiffType::NodeModified,
            property_changes: prop_changes,
          })
        }
      }
    }
  }

  // Check added nodes
  for tgt_n in target_nodes {
    let nid = tgt_n.id()
    if !base_graph.has_node(nid) {
      added_nodes.push(nid)
    }
  }

  // Check edges
  let added_edges = []
  let removed_edges = []
  let modified_edges = []

  let base_edges = base_graph.get_all_edges()
  let target_edges = target_graph.get_all_edges()

  for base_e in base_edges {
    let eid = base_e.id()
    match target_graph.get_edge(eid) {
      None => {
        removed_edges.push(eid)
        if base_e.flow_type() == @types.FlowType::SafetyInterlock ||
          base_e.flow_type() == @types.FlowType::EnergyFlow {
          breaking_changes.push(
            "Removed critical flow connection: " +
            eid +
            " (" +
            base_e.source_id() +
            " -> " +
            base_e.target_id() +
            ")",
          )
        }
      }
      Some(tgt_e) =>
        if base_e.bandwidth() != tgt_e.bandwidth() {
          modified_edges.push({
            edge_id: eid,
            source_id: base_e.source_id(),
            target_id: base_e.target_id(),
            flow_type: base_e.flow_type(),
            diff_type: EdgeDiffType::EdgeModified,
            old_bandwidth: base_e.bandwidth(),
            new_bandwidth: tgt_e.bandwidth(),
          })
        }
    }
  }

  for tgt_e in target_edges {
    let eid = tgt_e.id()
    if !base_graph.has_edge(eid) {
      added_edges.push(eid)
    }
  }

  // Compute risk score
  let mut score = 0.0
  score = score + removed_nodes.length().to_double() * 15.0
  score = score + removed_edges.length().to_double() * 10.0
  score = score + breaking_changes.length().to_double() * 20.0
  score = score + modified_nodes.length().to_double() * 5.0

  if score > 100.0 {
    score = 100.0
  }

  let risk_level = if score >= 70.0 {
    MigrationRiskLevel::CriticalRisk
  } else if score >= 40.0 {
    MigrationRiskLevel::HighRisk
  } else if score >= 15.0 {
    MigrationRiskLevel::MediumRisk
  } else {
    MigrationRiskLevel::LowRisk
  }

  {
    added_nodes,
    removed_nodes,
    modified_nodes,
    added_edges,
    removed_edges,
    modified_edges,
    overall_risk_level: risk_level,
    risk_score: score,
    breaking_changes,
    mitigation_recommendations: recommendations,
  }
}