;; lib/dream/tests/websocket.sx — upgrade, send/receive/close, broadcast.

(define dream-ws-pass 0)
(define dream-ws-fail 0)
(define dream-ws-fails (list))

(define
  dream-ws-test
  (fn
    (name actual expected)
    (if
      (= actual expected)
      (set! dream-ws-pass (+ dream-ws-pass 1))
      (begin
        (set! dream-ws-fail (+ dream-ws-fail 1))
        (append! dream-ws-fails {:name name :actual actual :expected expected})))))

;; ── upgrade response ───────────────────────────────────────────────
(define dream-ws-echo (fn (ws) (dream-text "unused")))
(define
  dream-ws-up
  ((dream-websocket dream-ws-echo) (dream-request "GET" "/ws" {} "")))
(dream-ws-test "upgrade status 101" (dream-status dream-ws-up) 101)
(dream-ws-test "is a websocket response" (dream-websocket? dream-ws-up) true)
(dream-ws-test
  "plain response is not ws"
  (dream-websocket? (dream-html "x"))
  false)
(dream-ws-test
  "upgrade header"
  (dream-resp-header dream-ws-up "upgrade")
  "websocket")

;; ── basic send / receive / close on a mock ─────────────────────────
(define dream-ws-w1 (dream-mock-ws (list "hi" "there")))
(dream-ws-test "open initially" (dream-ws-open? dream-ws-w1) true)
(dream-ws-test "receive first" (dream-receive dream-ws-w1) "hi")
(dream-ws-test "receive second" (dream-receive dream-ws-w1) "there")
(dream-ws-test "receive empty -> nil" (dream-receive dream-ws-w1) nil)
(dream-send dream-ws-w1 "out1")
(dream-send dream-ws-w1 "out2")
(dream-ws-test
  "sent recorded"
  (dream-ws-sent dream-ws-w1)
  (list "out1" "out2"))
(dream-close dream-ws-w1)
(dream-ws-test "closed flag" (dream-ws-closed? dream-ws-w1) true)
(dream-ws-test "open? false after close" (dream-ws-open? dream-ws-w1) false)

;; ── echo handler driven over the upgrade response ──────────────────
(define
  dream-ws-echo-h
  (fn
    (ws)
    (let
      ((m (dream-receive ws)))
      (if
        (nil? m)
        (dream-close ws)
        (begin (dream-send ws (str "echo:" m)) (dream-ws-echo-h ws))))))
(define
  dream-ws-echo-up
  ((dream-websocket dream-ws-echo-h)
    (dream-request "GET" "/ws" {} "")))
(define dream-ws-echo-conn (dream-mock-ws (list "a" "b" "c")))
(dream-ws-run dream-ws-echo-up dream-ws-echo-conn)
(dream-ws-test
  "echo all messages"
  (dream-ws-sent dream-ws-echo-conn)
  (list "echo:a" "echo:b" "echo:c"))
(dream-ws-test
  "echo closes at end"
  (dream-ws-closed? dream-ws-echo-conn)
  true)

;; ── broadcast to a room ────────────────────────────────────────────
(define dream-ws-c1 (dream-mock-ws (list)))
(define dream-ws-c2 (dream-mock-ws (list)))
(define dream-ws-c3 (dream-mock-ws (list)))
(dream-ws-broadcast (list dream-ws-c1 dream-ws-c2 dream-ws-c3) "hello room")
(dream-ws-test
  "broadcast c1"
  (dream-ws-sent dream-ws-c1)
  (list "hello room"))
(dream-ws-test
  "broadcast c2"
  (dream-ws-sent dream-ws-c2)
  (list "hello room"))
(dream-ws-test
  "broadcast c3"
  (dream-ws-sent dream-ws-c3)
  (list "hello room"))

(define dream-ws-tests-run! (fn () {:total (+ dream-ws-pass dream-ws-fail) :passed dream-ws-pass :failed dream-ws-fail :fails dream-ws-fails}))
