///|
pub(all) enum CycleClassification {
  ValidPalletRecirculationLoop
  DeadlockingMaterialDependency
} derive(Debug, Eq)

///|
pub(all) struct DetectedCycle {
  nodes : Array[String]
  classification : CycleClassification
  description : String
} derive(Debug)

///|
pub fn detect_material_cycles(
  graph : @graph.FactoryGraph,
) -> Array[DetectedCycle] {
  let sccs = strongly_connected_components(
    graph,
    flow_type=@types.FlowType::MaterialFlow,
  )
  let cycles = []

  for scc in sccs {
    if scc.length() > 1 {
      // Check if this SCC is a buffer/conveyor return loop or workstation deadlock
      let mut workstation_count = 0
      for nid in scc {
        match graph.get_node(nid) {
          Some(n) =>
            if n.node_type() == @types.NodeType::Workstation ||
              n.node_type() == @types.NodeType::Machine {
              workstation_count = workstation_count + 1
            }
          None => ()
        }
      }

      let (classification, desc) = if workstation_count <= 1 {
        (
          CycleClassification::ValidPalletRecirculationLoop,
          "Pallet or carrier return conveyor loop with " +
          scc.length().to_string() +
          " transport nodes",
        )
      } else {
        (
          CycleClassification::DeadlockingMaterialDependency,
          "Potentially deadlocking circular dependency among " +
          workstation_count.to_string() +
          " processing workstations",
        )
      }

      cycles.push({ nodes: scc, classification, description: desc })
    }
  }

  cycles
}