// Phase 3: state connections (non-resource edges).
//
// Modifier  : a source node's value adds to a resource edge's rate
//             (round(value * factor)); enables feedback loops such as
//             "more buildings -> faster production".
// Activator : a source node's value gates a target node or resource edge —
//             enabled iff value >= factor, otherwise the target does not fire /
//             the edge does not flow.
//
// All conditions read the pre-step snapshot (`state.values`) so results do not
// depend on edge processing order within a step. (Trigger / RateLabel are not
// wired yet.)

///|
/// Sum of Modifier contributions to resource edge `ei`.
fn modifier_bonus(diagram : Diagram, state : SimState, ei : Int) -> Int {
  let mut bonus = 0
  for se in diagram.states {
    if se.kind == Modifier {
      match se.to_edge {
        Some(t) =>
          if t == ei {
            bonus = bonus +
              (state.values[se.from].to_double() * se.factor).to_int()
          }
        None => ()
      }
    }
  }
  bonus
}

///|
/// `base` rate of edge `ei` plus its modifiers, clamped to >= 0.
fn effective_rate(
  diagram : Diagram,
  state : SimState,
  ei : Int,
  base : Int,
) -> Int {
  let w = base + modifier_bonus(diagram, state, ei)
  if w < 0 {
    0
  } else {
    w
  }
}

///|
/// True if any Activator targeting resource edge `ei` is unsatisfied.
fn edge_blocked(diagram : Diagram, state : SimState, ei : Int) -> Bool {
  for se in diagram.states {
    if se.kind == Activator {
      match se.to_edge {
        Some(t) =>
          if t == ei && state.values[se.from].to_double() < se.factor {
            return true
          }
        None => ()
      }
    }
  }
  false
}

///|
/// True if any Activator targeting node `idx` is unsatisfied.
fn node_blocked(diagram : Diagram, state : SimState, idx : Int) -> Bool {
  for se in diagram.states {
    if se.kind == Activator {
      match se.to_node {
        Some(t) =>
          if t == idx && state.values[se.from].to_double() < se.factor {
            return true
          }
        None => ()
      }
    }
  }
  false
}