; Tcl-on-SX coroutine tests (Phase 6)
(define tcl-coro-pass 0)
(define tcl-coro-fail 0)
(define tcl-coro-failures (list))

(define
  tcl-coro-assert
  (fn
    (label expected actual)
    (if
      (equal? expected actual)
      (set! tcl-coro-pass (+ tcl-coro-pass 1))
      (begin
        (set! tcl-coro-fail (+ tcl-coro-fail 1))
        (append!
          tcl-coro-failures
          (str label ": expected=" (str expected) " got=" (str actual)))))))

(define
  tcl-run-coro-tests
  (fn
    ()
    (set! tcl-coro-pass 0)
    (set! tcl-coro-fail 0)
    (set! tcl-coro-failures (list))
    (define interp (fn () (make-default-tcl-interp)))
    (define run (fn (src) (tcl-eval-string (interp) src)))
    (define
      ok
      (fn (label actual expected) (tcl-coro-assert label expected actual)))

    ; --- basic coroutine: yields one value ---
    (ok "coro-single-yield"
      (get (run "proc gen {} { yield hello }\ncoroutine g gen\ng") :result)
      "hello")

    ; --- coroutine yields multiple values in order ---
    (ok "coro-multi-yield-1"
      (get (run "proc cnt {} { yield a; yield b; yield c }\ncoroutine c1 cnt\nc1") :result)
      "a")

    (ok "coro-multi-yield-2"
      (get (run "proc cnt {} { yield a; yield b; yield c }\ncoroutine c1 cnt\nc1\nc1") :result)
      "b")

    (ok "coro-multi-yield-3"
      (get (run "proc cnt {} { yield a; yield b; yield c }\ncoroutine c1 cnt\nc1\nc1\nc1") :result)
      "c")

    ; --- coroutine with arguments to proc ---
    (ok "coro-args"
      (get (run "proc gen2 {n} { yield $n; yield [expr {$n + 1}] }\ncoroutine g2 gen2 10\ng2") :result)
      "10")

    (ok "coro-args-2"
      (get (run "proc gen2 {n} { yield $n; yield [expr {$n + 1}] }\ncoroutine g2 gen2 10\ng2\ng2") :result)
      "11")

    ; --- coroutine exhausted returns empty string ---
    (ok "coro-exhausted"
      (get (run "proc g3 {} { yield only }\ncoroutine c3 g3\nc3\nc3") :result)
      "")

    ; --- yield in while loop ---
    (ok "coro-while-loop-1"
      (get (run "proc counter {max} { set i 0; while {$i < $max} { yield $i; incr i } }\ncoroutine cw counter 3\ncw") :result)
      "0")

    (ok "coro-while-loop-2"
      (get (run "proc counter {max} { set i 0; while {$i < $max} { yield $i; incr i } }\ncoroutine cw counter 3\ncw\ncw") :result)
      "1")

    (ok "coro-while-loop-3"
      (get (run "proc counter {max} { set i 0; while {$i < $max} { yield $i; incr i } }\ncoroutine cw counter 3\ncw\ncw\ncw") :result)
      "2")

    ; --- collect all yields from coroutine ---
    (ok "coro-collect-all"
      (get
        (run
          "proc counter {n max} { while {$n < $max} { yield $n; incr n }; yield done }\ncoroutine gen1 counter 0 3\nset out {}\nfor {set i 0} {$i < 4} {incr i} { lappend out [gen1] }\nlindex $out 3")
        :result)
      "done")

    ; --- two independent coroutines ---
    (ok "coro-two-independent"
      (get
        (run
          "proc seq {start} { yield $start; yield [expr {$start+1}] }\ncoroutine ca seq 0\ncoroutine cb seq 10\nset r [ca]\nappend r \":\" [cb]")
        :result)
      "0:10")

    ; --- yield with no value returns empty string ---
    (ok "coro-yield-no-val"
      (get (run "proc g {} { yield }\ncoroutine cg g\ncg") :result)
      "")

    ; --- clock seconds ---
    (ok "clock-seconds"
      (> (parse-int (get (run "clock seconds") :result)) 0)
      true)

    ; --- clock milliseconds ---
    (ok "clock-milliseconds"
      (> (parse-int (get (run "clock milliseconds") :result)) 0)
      true)

    ; --- clock format stub ---
    (ok "clock-format"
      (get (run "clock format 0") :result)
      "Thu Jan  1 00:00:00 UTC 1970")

    ; --- file stubs ---
    (ok "file-exists-stub"
      (get (run "file exists /no/such/file") :result)
      "0")

    (ok "file-join"
      (get (run "file join foo bar baz") :result)
      "foo/bar/baz")

    (ok "open-returns-channel"
      (get (run "open /dev/null r") :result)
      "file0")

    (ok "eof-returns-1"
      (get (run "set ch [open /dev/null r]\nread $ch\neof $ch") :result)
      "1")

    (dict
      "passed"
      tcl-coro-pass
      "failed"
      tcl-coro-fail
      "failures"
      tcl-coro-failures)))
