; feed/dedupe — collapse duplicate items, keeping first occurrence per key.
; Each verb may want its own key (see briefing): "alice posted X" keys on
; (actor verb object) — distinct per actor; "alice liked X / bob liked X"
; collapse on (verb object) so the cross-actor likes fold into one.
;
; Requires: lib/feed/normalize.sx, lib/feed/stream.sx, lib/feed/fanout.sx
; (feed/-elem? lives in fanout.sx).

; generic: dedupe a stream by key-fn, first occurrence wins (stable)
(define
  feed/-dedup-by
  (fn
    (items key-fn)
    (get
      (reduce
        (fn
          (st x)
          (let
            ((k (key-fn x)))
            (if (feed/-elem? k (get st :seen)) st {:seen (append (get st :seen) (list k)) :out (append (get st :out) (list x))})))
        {:seen (list) :out (list)}
        items)
      :out)))

(define
  feed/dedupe
  (fn
    (stream key-fn)
    (feed/stream (feed/-dedup-by (feed/items stream) key-fn))))

; --- keys -------------------------------------------------------------------

(define
  feed/activity-key
  (fn (a) (list (get a :actor) (get a :verb) (get a :object))))

; collapse cross-actor duplicates of the same verb+object (e.g. likes)
(define feed/collapse-key (fn (a) (list (get a :verb) (get a :object))))

; per-receiver inbox key — one inbox event per (receiver, actor, verb, object)
(define
  feed/event-key
  (fn
    (ev)
    (let
      ((a (get ev :activity)))
      (list (get ev :to) (get a :actor) (get a :verb) (get a :object)))))

; verbs whose duplicates collapse across actors (reactions, not authorship).
; rebindable: callers can (set! feed/collapse-verbs ...) to tune the policy.
(define
  feed/collapse-verbs
  (list "like" "favourite" "follow" "boost" "repost"))

; per-verb key: collapse-verbs fold on (verb object); the rest key on
; (actor verb object).
(define
  feed/smart-key
  (fn
    (a)
    (if
      (feed/-elem? (get a :verb) feed/collapse-verbs)
      (feed/collapse-key a)
      (feed/activity-key a))))

; --- ready-made dedupers ----------------------------------------------------

(define feed/dedupe-activities (fn (s) (feed/dedupe s feed/activity-key)))

(define feed/dedupe-collapse (fn (s) (feed/dedupe s feed/collapse-key)))

; verb-aware: reactions collapse cross-actor, posts stay distinct per actor
(define feed/dedupe-smart (fn (s) (feed/dedupe s feed/smart-key)))

; dedupe an inbox: at most one event per receiver per (actor verb object)
(define feed/dedupe-inbox (fn (inbox) (feed/dedupe inbox feed/event-key)))
