;; lib/mod/tests/decide.sx — Phase 1: report representation + simple policy.

(define mod-dec-count 0)
(define mod-dec-pass 0)
(define mod-dec-fail 0)
(define mod-dec-failures (list))

(define
  mod-dec-test!
  (fn
    (name got expected)
    (begin
      (set! mod-dec-count (+ mod-dec-count 1))
      (if
        (= got expected)
        (set! mod-dec-pass (+ mod-dec-pass 1))
        (begin
          (set! mod-dec-fail (+ mod-dec-fail 1))
          (append!
            mod-dec-failures
            (str name "\n    expected: " expected "\n    got:      " got)))))))

;; decide a single report (count over a 1-element registry)
(define
  mod-dec-one
  (fn
    (reason)
    (let
      ((r (mod/mk-report "r1" "alice" "bob" reason)))
      (mod/decide-report r (list r) mod/default-rules))))

(define mod-dec-action (fn (reason) (get (mod-dec-one reason) :action)))

;; ── spam keyword → :hide ──

(mod-dec-test!
  "spam keyword 'spam' → hide"
  (mod-dec-action "this is spam")
  "hide")
(mod-dec-test!
  "spam keyword 'buy now' → hide"
  (mod-dec-action "buy now while stocks last")
  "hide")
(mod-dec-test!
  "spam keyword case-insensitive 'CLICK HERE' → hide"
  (mod-dec-action "CLICK HERE now")
  "hide")
(mod-dec-test!
  "spam keyword 'free money' → hide"
  (mod-dec-action "win free money fast")
  "hide")

;; ── abuse keyword → :remove ──

(mod-dec-test!
  "abuse keyword 'harassment' → remove"
  (mod-dec-action "ongoing harassment of users")
  "remove")
(mod-dec-test!
  "abuse keyword 'threat' → remove"
  (mod-dec-action "this is a threat")
  "remove")
(mod-dec-test!
  "abuse keyword 'slur' → remove"
  (mod-dec-action "contains a slur")
  "remove")

;; ── no rule → :keep ──

(mod-dec-test!
  "neutral reason → keep"
  (mod-dec-action "I disagree with this post")
  "keep")
(mod-dec-test! "empty reason → keep" (mod-dec-action "") "keep")

;; ── decision carries the matching rule (proof, not bare keyword) ──

(mod-dec-test!
  "spam decision rule name"
  (get (mod-dec-one "this is spam") :rule)
  "spam-hide")
(mod-dec-test!
  "keep decision rule name"
  (get (mod-dec-one "fine post") :rule)
  "default-keep")
(mod-dec-test!
  "abuse decision rule name"
  (get (mod-dec-one "harassment here") :rule)
  "abuse-remove")
(mod-dec-test!
  "spam proof :rule"
  (get (get (mod-dec-one "spam!") :proof) :rule)
  "spam-hide")
(mod-dec-test!
  "spam proof :evidence"
  (get (get (mod-dec-one "spam!") :proof) :evidence)
  (list "spam"))
(mod-dec-test!
  "spam proof :count"
  (get (get (mod-dec-one "spam!") :proof) :count)
  1)

;; ── classification (evidence derivation) ──

(mod-dec-test!
  "classify spam"
  (mod/classify-keywords (mod/mk-report "r1" "a" "b" "spam!"))
  (list "spam"))
(mod-dec-test!
  "classify abuse"
  (mod/classify-keywords (mod/mk-report "r1" "a" "b" "abuse"))
  (list "abuse"))
(mod-dec-test!
  "classify neutral → empty"
  (mod/classify-keywords (mod/mk-report "r1" "a" "b" "hello"))
  (list))
(mod-dec-test!
  "classify both spam+abuse"
  (mod/classify-keywords (mod/mk-report "r1" "a" "b" "spam and abuse"))
  (list "spam" "abuse"))

;; ── report-count + repeated → :escalate ──

(define
  mod-dec-three
  (list
    (mod/mk-report "r1" "a" "bob" "x")
    (mod/mk-report "r2" "c" "bob" "y")
    (mod/mk-report "r3" "d" "bob" "z")))

(mod-dec-test!
  "report-count counts subject"
  (mod/report-count "bob" mod-dec-three)
  3)
(mod-dec-test!
  "3 reports about subject → escalate"
  (get
    (mod/decide-report (first mod-dec-three) mod-dec-three mod/default-rules)
    :action)
  "escalate")
(mod-dec-test!
  "escalate rule name"
  (get
    (mod/decide-report (first mod-dec-three) mod-dec-three mod/default-rules)
    :rule)
  "repeated-escalate")

(define
  mod-dec-two
  (list
    (mod/mk-report "r1" "a" "carol" "x")
    (mod/mk-report "r2" "c" "carol" "y")))

(mod-dec-test!
  "2 reports about subject → keep (below threshold)"
  (get
    (mod/decide-report (first mod-dec-two) mod-dec-two mod/default-rules)
    :action)
  "keep")

;; ── precedence: spam beats repeated ──

(define
  mod-dec-spam-among-many
  (list
    (mod/mk-report "r1" "a" "dave" "buy now spam")
    (mod/mk-report "r2" "c" "dave" "y")
    (mod/mk-report "r3" "d" "dave" "z")))

(mod-dec-test!
  "spam wins over repeated (precedence)"
  (get
    (mod/decide-report
      (first mod-dec-spam-among-many)
      mod-dec-spam-among-many
      mod/default-rules)
    :action)
  "hide")

;; ── accessors ──

(mod-dec-test!
  "report-about accessor"
  (mod/report-about (mod/mk-report "r1" "a" "bob" "x"))
  "bob")
(mod-dec-test!
  "report-by accessor"
  (mod/report-by (mod/mk-report "r1" "alice" "bob" "x"))
  "alice")

;; ── api registry ──

(mod/reset!)
(define mod-dec-r1 (mod/report "alice" "bob" "this is spam"))
(define mod-dec-r2 (mod/report "carol" "eve" "fine post"))

(mod-dec-test!
  "mod/report assigns sequential id r1"
  (mod/report-id mod-dec-r1)
  "r1")
(mod-dec-test!
  "mod/report assigns sequential id r2"
  (mod/report-id mod-dec-r2)
  "r2")
(mod-dec-test!
  "mod/decide via registry → hide"
  (get (mod/decide "r1") :action)
  "hide")
(mod-dec-test!
  "mod/decide via registry → keep"
  (get (mod/decide "r2") :action)
  "keep")
(mod-dec-test! "mod/decide unknown id → nil" (mod/decide "r99") nil)

(define mod-decide-tests-run! (fn () {:failures mod-dec-failures :total mod-dec-count :passed mod-dec-pass :failed mod-dec-fail}))
