;; lib/host/tests/middleware.sx — auth (bearer -> principal), ACL gate, and error
;; trapping, composed via host/pipeline. ACL facts: alice may "post" on "feed".

(define host-mw-pass 0)
(define host-mw-fail 0)
(define host-mw-fails (list))

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

;; ── fixtures ───────────────────────────────────────────────────────
(acl/load! (list (acl-grant "alice" "post" "feed")))

(define host-mw-resolve
  (fn (tok) (if (= tok "good") "alice" nil)))

(define host-mw-handler
  (fn (req) (host/ok-status 201 (host/principal req))))

;; protected: needs auth + post/feed permission
(define host-mw-protected
  (host/pipeline
    (list
      (host/require-auth host-mw-resolve)
      (host/require-permission "post" (fn (req) "feed")))
    host-mw-handler))

;; protected with an action alice is NOT granted
(define host-mw-protected-del
  (host/pipeline
    (list
      (host/require-auth host-mw-resolve)
      (host/require-permission "delete" (fn (req) "feed")))
    host-mw-handler))

(define
  host-mw-req
  (fn (auth)
    (dream-request "POST" "/feed"
      (if auth {:authorization auth} {})
      "")))

;; ── auth ───────────────────────────────────────────────────────────
(host-mw-test
  "no token -> 401"
  (dream-status (host-mw-protected (host-mw-req nil)))
  401)
(host-mw-test
  "401 has www-authenticate"
  (dream-resp-header (host-mw-protected (host-mw-req nil)) "www-authenticate")
  "Bearer")
(host-mw-test
  "bad token -> 401"
  (dream-status (host-mw-protected (host-mw-req "Bearer wrong")))
  401)

;; ── authz ──────────────────────────────────────────────────────────
(host-mw-test
  "authed + permitted -> 201"
  (dream-status (host-mw-protected (host-mw-req "Bearer good")))
  201)
(host-mw-test
  "principal threaded to handler"
  (contains?
    (dream-resp-body (host-mw-protected (host-mw-req "Bearer good")))
    ":data \"alice\"")
  true)
(host-mw-test
  "authed but not permitted -> 403"
  (dream-status (host-mw-protected-del (host-mw-req "Bearer good")))
  403)
(host-mw-test
  "403 envelope"
  (contains?
    (dream-resp-body (host-mw-protected-del (host-mw-req "Bearer good")))
    ":error \"forbidden\"")
  true)

;; ── error trapping ─────────────────────────────────────────────────
(define host-mw-boom (fn (req) (error "kaboom")))
(host-mw-test
  "wrap-errors -> 500"
  (dream-status ((host/wrap-errors host-mw-boom) (host-mw-req nil)))
  500)
(host-mw-test
  "500 envelope"
  (contains?
    (dream-resp-body ((host/wrap-errors host-mw-boom) (host-mw-req nil)))
    ":ok false")
  true)

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