;; Tests for perform/IO suspension chaining through for-each
;; Bug: after resume from first perform inside for-each,
;; subsequent iterations' performs don't suspend — they complete
;; synchronously, breaking multi-step async sequences like test runners.

(defsuite
  "perform-for-each-chain"
  (deftest
    "for-each with perform suspends on each iteration"
    (let
      ((state1 (cek-step-loop (make-cek-state (quote (let ((results (list))) (for-each (fn (item) (let ((val (perform {:op "fetch" :key item}))) (append! results val))) (list "a" "b" "c")) results)) (make-env) (list)))))
      (assert-true (cek-suspended? state1))
      (assert= "a" (get (cek-io-request state1) :key))
      (let
        ((state2 (cek-resume state1 "result-a")))
        (assert-true (cek-suspended? state2))
        (assert= "b" (get (cek-io-request state2) :key))
        (let
          ((state3 (cek-resume state2 "result-b")))
          (assert-true (cek-suspended? state3))
          (assert= "c" (get (cek-io-request state3) :key))
          (let
            ((final (cek-resume state3 "result-c")))
            (assert-true (cek-terminal? final))
            (assert= 3 (len (cek-value final))))))))
  (deftest
    "for-each with guard and perform chains correctly"
    (let
      ((state1 (cek-step-loop (make-cek-state (quote (let ((results (list))) (for-each (fn (item) (guard (e (true (append! results (str "fail:" item)))) (let ((val (perform {:op "fetch" :key item}))) (append! results (str "ok:" val))))) (list "x" "y")) results)) (make-env) (list)))))
      (assert-true (cek-suspended? state1))
      (let
        ((state2 (cek-resume state1 "X")))
        (assert-true (cek-suspended? state2))
        (let
          ((final (cek-resume state2 "Y")))
          (assert-true (cek-terminal? final))
          (let
            ((results (cek-value final)))
            (assert= 2 (len results))
            (assert= "ok:X" (nth results 0))
            (assert= "ok:Y" (nth results 1)))))))
  (deftest
    "nested performs in for-each — reload + wait pattern"
    (let
      ((state1 (cek-step-loop (make-cek-state (quote (let ((log (list))) (for-each (fn (name) (perform {:op "wait" :ms 1000}) (append! log (str "reloaded:" name)) (perform {:op "wait" :ms 500}) (append! log (str "done:" name))) (list "t1" "t2")) log)) (make-env) (list)))))
      (assert-true (cek-suspended? state1))
      (assert= 1000 (get (cek-io-request state1) :ms))
      (let
        ((s2 (cek-resume state1 nil)))
        (assert-true (cek-suspended? s2))
        (assert= 500 (get (cek-io-request s2) :ms))
        (let
          ((s3 (cek-resume s2 nil)))
          (assert-true (cek-suspended? s3))
          (assert= 1000 (get (cek-io-request s3) :ms))
          (let
            ((s4 (cek-resume s3 nil)))
            (assert-true (cek-suspended? s4))
            (assert= 500 (get (cek-io-request s4) :ms))
            (let
              ((final (cek-resume s4 nil)))
              (assert-true (cek-terminal? final))
              (assert= 4 (len (cek-value final))))))))))