///|
pub(all) struct BufferTuningRecommendation {
  buffer_id : String
  upstream_station_id : String
  downstream_station_id : String
  current_capacity : Double
  recommended_capacity : Double
  rationale : String
} derive(Debug, Eq)

///|
pub fn optimize_buffer_capacities(
  graph : @graph.FactoryGraph,
) -> Array[BufferTuningRecommendation] {
  let recs : Array[BufferTuningRecommendation] = []
  let nodes = graph.get_all_nodes()

  for node in nodes {
    if node.node_type() == @types.NodeType::Buffer {
      let bid = node.id()
      let in_e = graph.get_layer_in_edges(@types.FlowType::MaterialFlow, bid)
      let out_e = graph.get_layer_out_edges(@types.FlowType::MaterialFlow, bid)

      let up_id = if in_e.length() > 0 { in_e[0].source_id() } else { "N/A" }
      let down_id = if out_e.length() > 0 {
        out_e[0].target_id()
      } else {
        "N/A"
      }

      let up_node = graph.get_node(up_id)
      let mttr = match up_node {
        Some(un) => un.mttr_hours()
        None => 1.5
      }
      let cycle_time = match up_node {
        Some(un) => un.cycle_time_sec()
        None => 30.0
      }

      let current_cap = node.capacity()
      // Recommended buffer size: absorb MTTR duration * production rate
      let rate_per_hour = if cycle_time > 0.0 {
        3600.0 / cycle_time
      } else {
        100.0
      }
      let recommended = rate_per_hour * mttr * 0.5

      let rationale = "Calculated buffer size to absorb " +
        mttr.to_string() +
        "h upstream MTTR variance with 50% decoupling safety margin."

      recs.push({
        buffer_id: bid,
        upstream_station_id: up_id,
        downstream_station_id: down_id,
        current_capacity: current_cap,
        recommended_capacity: recommended,
        rationale,
      })
    }
  }

  recs
}