// Small helper functions used by examples that drive AdExSinExp
// posts from IF pre-neurons (since `SpikingSynapse` is currently
// hardcoded to IF-to-IF in the connection_spiking module).
//
// These helpers provide:
//   - `make_random_weights(n_pre, n_post, mu, p, rng)` — Bernoulli
//     connectivity, returns dense n_pre × n_post Array[Float] of
//     connection weights (0 for non-connections, mu for connections).
//   - `route_pre_to_post(pre, post, weights, exc, inh)` — for each
//     pre-neuron that fires, add its outgoing weights to post.glu
//     (exc) or post.gaba (inh).
//   - `simulate_step_if(pop, dt)` — convenience wrapper for the
//     three IF integrate steps (step_synapses + synaptic_current
//     + step_neuron).
//   - `count_nnz(arr)` — count non-zero entries in Array[Float].

///|
/// Build a dense n_pre × n_post weight matrix with Bernoulli(p)
/// connectivity. Connections get weight `mu`; non-connections are 0.
pub fn make_random_weights(
  n_pre : Int,
  n_post : Int,
  mu : Float,
  p : Float,
  rng : Xoshiro,
) -> Array[Float] {
  let total = n_pre * n_post
  let arr : Array[Float] = Array::make(total, 0.0F)
  for k in 0.. Unit {
  let n_pre = pre.n
  let n_post = post.n
  for i in 0.. Unit {
  step_synapses(pop, dt)
  synaptic_current(pop)
  step_neuron(pop, dt)
}

///|
/// Count non-zero entries in a Float array.
pub fn count_nnz(arr : Array[Float]) -> Int {
  let mut n = 0
  for k in 0.. Int {
  let mut n = 0
  for k in 0.. 0.0F {
      n = n + 1
    }
  }
  n
}

///|
/// Compute the firing rate in Hz from a fire monitor's data array
/// (each entry is 0.0F or 1.0F per step). With dt=0.125ms, each
/// step is 0.000125s = 0.125ms = 0.125/1000 s.
/// rate_Hz = count / (n_steps * dt) = count / (n_steps * 0.000125)
/// Internal rate (in 0.001 Hz units) = count / (n_steps * 0.125)
pub fn monitor_firing_rate(data : Array[Float]) -> Float {
  let n = data.length()
  if n == 0 {
    return 0.0F
  }
  let count = monitor_count_spikes(data)
  // Each step is 0.125ms. Total sim time = n * 0.125 ms.
  // Hz = spikes/sec = count / (n * 0.125 / 1000) = count * 8000 / n
  let rate_hz : Float = Float::from_int(count) * 8000.0F / Float::from_int(n)
  rate_hz
}