// Benchmarks for signals library

///|
test "bench: signal get/set" (b : @bench.T) {
  let sig = signal(0)
  b.bench(name="signal_set", fn() { sig.set(1) })
  b.bench(name="signal_get", fn() { b.keep(sig.get()) })
}

///|
test "bench: memo computation" (b : @bench.T) {
  let a = signal(1)
  let b_sig = signal(2)
  let sum = memo(fn() { a.get() + b_sig.get() })

  // Warm up - ensure memo is initialized
  let _ = sum()
  b.bench(name="memo_cached", fn() { b.keep(sum()) })
  b.bench(name="memo_recompute", fn() {
    a.set(a.peek() + 1)
    b.keep(sum())
  })
}

///|
test "bench: render_effect" (b : @bench.T) {
  let sig = signal(0)
  let counter = Ref::new(0)
  let dispose = render_effect(fn() {
    let _ = sig.get()
    counter.val = counter.val + 1
  })
  b.bench(name="effect_trigger", fn() { sig.set(sig.peek() + 1) })
  dispose()
  b.keep(counter.val)
}

///|
test "bench: batch vs non-batch" (b : @bench.T) {
  let a = signal(0)
  let b_sig = signal(0)
  let counter = Ref::new(0)
  let dispose = render_effect(fn() {
    let _ = a.get() + b_sig.get()
    counter.val = counter.val + 1
  })
  b.bench(name="no_batch", fn() {
    a.set(a.peek() + 1)
    b_sig.set(b_sig.peek() + 1)
  })
  b.bench(name="with_batch", fn() {
    batch(fn() {
      a.set(a.peek() + 1)
      b_sig.set(b_sig.peek() + 1)
    })
  })
  dispose()
  b.keep(counter.val)
}

///|
test "bench: deep dependency chain" (b : @bench.T) {
  let source = signal(0)
  let m1 = memo(fn() { source.get() + 1 })
  let m2 = memo(fn() { m1() + 1 })
  let m3 = memo(fn() { m2() + 1 })
  let m4 = memo(fn() { m3() + 1 })

  // Warm up
  let _ = m4()
  b.bench(name="deep_chain_read", fn() { b.keep(m4()) })
  b.bench(name="deep_chain_update", fn() {
    source.set(source.peek() + 1)
    b.keep(m4())
  })
}

///|
test "bench: many subscribers" (b : @bench.T) {
  let sig = signal(0)
  let disposers : Array[() -> Unit] = []
  let counter = Ref::new(0)

  // Create 100 effects subscribing to the same signal
  for i = 0; i < 100; i = i + 1 {
    disposers.push(
      render_effect(fn() {
        let _ = sig.get()
        counter.val = counter.val + 1
      }),
    )
  }
  b.bench(name="notify_100_subscribers", fn() { sig.set(sig.peek() + 1) })

  // Cleanup
  for i = 0; i < disposers.length(); i = i + 1 {
    disposers[i]()
  }
  b.keep(counter.val)
}