;; lib/host/tests/feed.sx — the migrated feed endpoints, GET /feed (read) and
;; POST /feed (guarded write). Includes a golden test: the host read response
;; body must equal the feed subsystem's own recent-first stream wrapped in the
;; standard envelope — the endpoint adds the HTTP/JSON shell and nothing else.

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

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

(define
  host-fd-req
  (fn (target) (dream-request "GET" target {} "")))

(define
  host-fd-app
  (host/make-app (list host/feed-routes)))

;; ── empty feed ─────────────────────────────────────────────────────
(feed/reset!)
(host-fd-test
  "empty feed 200"
  (dream-status (host-fd-app (host-fd-req "/feed")))
  200)
(host-fd-test
  "empty feed data ()"
  (contains? (dream-resp-body (host-fd-app (host-fd-req "/feed"))) ":data ()")
  true)

;; ── seeded feed ────────────────────────────────────────────────────
(feed/reset!)
(feed/post {:actor "alice" :verb "post" :object "p1" :at 1})
(feed/post {:actor "bob" :verb "post" :object "p2" :at 2})
(feed/post {:actor "alice" :verb "like" :object "p2" :at 3})

;; recent-first: newest activity (at 3) leads, so its marker precedes the oldest.
(host-fd-test
  "timeline recent-first"
  (let ((body (dream-resp-body (host-fd-app (host-fd-req "/feed")))))
    (< (index-of body ":at 3") (index-of body ":at 1")))
  true)

;; actor filter: only alice's two activities.
(host-fd-test
  "actor filter count"
  (feed/count
    (feed/by-actor (feed/recent (feed/all)) "alice"))
  2)
(host-fd-test
  "actor filter excludes bob"
  (contains?
    (dream-resp-body (host-fd-app (host-fd-req "/feed?actor=alice")))
    "bob")
  false)

;; limit: cap to a single activity (the most recent).
(host-fd-test
  "limit caps results"
  (contains?
    (dream-resp-body (host-fd-app (host-fd-req "/feed?limit=1")))
    ":at 1")
  false)

;; ── golden: endpoint = subsystem recent stream + envelope ───────────
(host-fd-test
  "golden full timeline"
  (dream-resp-body (host-fd-app (host-fd-req "/feed")))
  (serialize {:ok true :data (feed/items (feed/recent (feed/all)))}))
(host-fd-test
  "golden actor-filtered"
  (dream-resp-body (host-fd-app (host-fd-req "/feed?actor=alice")))
  (serialize {:ok true :data (feed/items (feed/by-actor (feed/recent (feed/all)) "alice"))}))

;; ── write: POST /feed (auth + ACL + action) ────────────────────────
(acl/load! (list (acl-grant "alice" "post" "feed")))
(define host-fd-resolve (fn (tok) (if (= tok "good") "alice" nil)))
(define
  host-fd-wapp
  (host/make-app
    (list host/feed-routes (host/feed-write-routes host-fd-resolve))))
(define
  host-fd-post
  (fn (auth body)
    (dream-request "POST" "/feed" (if auth {:authorization auth} {}) body)))

(feed/reset!)
(host-fd-test
  "post no auth -> 401"
  (dream-status (host-fd-wapp (host-fd-post nil "{}")))
  401)
(host-fd-test
  "post unchanged feed after 401"
  (feed/size)
  0)
(host-fd-test
  "post authed+permitted -> 201"
  (dream-status
    (host-fd-wapp
      (host-fd-post
        "Bearer good"
        "{:actor \"alice\" :verb \"post\" :object \"p9\" :at 9}")))
  201)
(host-fd-test "post grew feed" (feed/size) 1)
(host-fd-test
  "created activity visible in timeline"
  (contains?
    (dream-resp-body (host-fd-wapp (host-fd-req "/feed")))
    "p9")
  true)
(host-fd-test
  "post non-object body -> 400"
  (dream-status (host-fd-wapp (host-fd-post "Bearer good" "(1 2)")))
  400)

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