;; lib/dream/tests/run.sx — app adapter + dream-run wiring.

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

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

;; ── app adapter: raw -> serialised response ────────────────────────
(define
  dream-rn-router
  (dream-router
    (list
      (dream-get "/" (fn (req) (dream-text "home")))
      (dream-get
        "/u/:id"
        (fn (req) (dream-text (str "u=" (dream-param req "id")))))
      (dream-post "/echo" (fn (req) (dream-text (dream-body req)))))))
(define dream-rn-app (dream-app dream-rn-router))

(define dream-rn-r1 (dream-rn-app {:method "GET" :target "/"}))
(dream-rn-test "serialised status" (get dream-rn-r1 :status) 200)
(dream-rn-test "serialised body" (get dream-rn-r1 :body) "home")
(dream-rn-test
  "serialised content-type"
  (get (get dream-rn-r1 :headers) "content-type")
  "text/plain; charset=utf-8")
(dream-rn-test
  "serialised set-cookies empty"
  (get dream-rn-r1 :set-cookies)
  (list))

(dream-rn-test
  "adapts target+params"
  (get (dream-rn-app {:method "GET" :target "/u/42"}) :body)
  "u=42")
(dream-rn-test "adapts body" (get (dream-rn-app {:body "ping" :method "POST" :target "/echo"}) :body) "ping")
(dream-rn-test
  "method defaults to GET"
  (get (dream-rn-app {:target "/"}) :body)
  "home")
(dream-rn-test
  "missing target -> /"
  (get (dream-rn-app {:method "GET"}) :status)
  200)
(dream-rn-test
  "unknown route 404"
  (get (dream-rn-app {:method "GET" :target "/nope"}) :status)
  404)

;; bare-string handler is coerced
(define dream-rn-bare (dream-app (fn (req) "plain")))
(dream-rn-test
  "coerces bare string status"
  (get (dream-rn-bare {:target "/"}) :status)
  200)
(dream-rn-test
  "coerces bare string body"
  (get (dream-rn-bare {:target "/"}) :body)
  "plain")

;; ── set-cookies flow through (session middleware) ──────────────────
(define
  dream-rn-sess-app
  (dream-app
    ((dream-sessions (dream-memory-sessions))
      (fn (req) (dream-text "ok")))))
(define dream-rn-sess-r (dream-rn-sess-app {:method "GET" :target "/"}))
(dream-rn-test
  "session set-cookie present"
  (len (get dream-rn-sess-r :set-cookies))
  1)
(dream-rn-test
  "session cookie content"
  (contains? (first (get dream-rn-sess-r :set-cookies)) "dream.session=")
  true)

;; ── websocket upgrade serialisation ────────────────────────────────
(define
  dream-rn-ws-app
  (dream-app (dream-websocket (fn (ws) (dream-close ws)))))
(define dream-rn-ws-r (dream-rn-ws-app {:method "GET" :target "/ws"}))
(dream-rn-test "ws upgrade status 101" (get dream-rn-ws-r :status) 101)
(dream-rn-test
  "ws handler carried"
  (not (nil? (get dream-rn-ws-r :websocket)))
  true)

;; ── dream-run wiring (mock listen captures the op) ─────────────────
(define dream-rn-captured nil)
(define
  dream-rn-listen
  (fn (op) (begin (set! dream-rn-captured op) :listening)))
(define
  dream-rn-result
  (dream-run-with dream-rn-listen dream-rn-router {:port 9000}))
(dream-rn-test "listen returns" dream-rn-result :listening)
(dream-rn-test "listen op kind" (get dream-rn-captured :op) "http/listen")
(dream-rn-test "listen port" (get dream-rn-captured :port) 9000)
(dream-rn-test
  "default port"
  (get
    (begin
      (dream-run-with dream-rn-listen dream-rn-router {})
      dream-rn-captured)
    :port)
  8080)
;; the captured app is runnable
(dream-rn-test
  "captured app serves"
  (get ((get dream-rn-captured :app) {:method "GET" :target "/"}) :body)
  "home")

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