;; lib/mod/tests/severity.sx — Ext 6: strictest-wins decision strategy.

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

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

;; ── severity ranking ──

(mod-sev-test! "ban most severe" (mod/action-severity "ban") 4)
(mod-sev-test!
  "remove > hide"
  (< (mod/action-severity "hide") (mod/action-severity "remove"))
  true)
(mod-sev-test! "keep least severe" (mod/action-severity "keep") 0)
(mod-sev-test!
  "escalate above keep"
  (< (mod/action-severity "keep") (mod/action-severity "escalate"))
  true)

;; ── strictest agrees with default-rules on simple cases ──

(define mod-sev-spam (mod/mk-report "r1" "a" "b" "this is spam"))
(mod-sev-test!
  "strictest spam → hide"
  (get
    (mod/decide-strictest mod-sev-spam (list mod-sev-spam) mod/default-rules)
    :action)
  "hide")
(define mod-sev-clean (mod/mk-report "r2" "a" "b" "a fine post"))
(mod-sev-test!
  "strictest clean → keep"
  (get
    (mod/decide-strictest
      mod-sev-clean
      (list mod-sev-clean)
      mod/default-rules)
    :action)
  "keep")
(mod-sev-test!
  "decision tagged strategy strictest"
  (get
    (mod/decide-strictest mod-sev-spam (list mod-sev-spam) mod/default-rules)
    :strategy)
  "strictest")

;; ── strictest diverges from first-match when order ≠ severity ──

(define
  mod-sev-rules
  (list
    (mod/mk-rule
      "early-escalate"
      :escalate (list (list :count-at-least 1)))
    (mod/mk-rule "spam-remove" :remove (list (list :classification "spam")))
    (mod/mk-rule "default-keep" :keep (list))))

(define mod-sev-r (mod/mk-report "r3" "a" "b" "this is spam"))

(mod-sev-test!
  "first-match picks earliest rule (escalate)"
  (get (mod/decide-report mod-sev-r (list mod-sev-r) mod-sev-rules) :action)
  "escalate")
(mod-sev-test!
  "strictest picks harshest action (remove)"
  (get
    (mod/decide-strictest mod-sev-r (list mod-sev-r) mod-sev-rules)
    :action)
  "remove")
(mod-sev-test!
  "strictest names the harshest rule"
  (get (mod/decide-strictest mod-sev-r (list mod-sev-r) mod-sev-rules) :rule)
  "spam-remove")
(mod-sev-test!
  "strictest carries proof goals"
  (len
    (get
      (get
        (mod/decide-strictest mod-sev-r (list mod-sev-r) mod-sev-rules)
        :proof)
      :goals))
  1)

;; ── strictest among three matches (spam + repeated) ──

(define mod-sev-rep (mod/mk-report "r4" "a" "b" "buy now spam"))
(define mod-sev-reps (list mod-sev-rep mod-sev-rep mod-sev-rep))
(mod-sev-test!
  "strictest among hide+escalate+keep → hide (default rules)"
  (get
    (mod/decide-strictest mod-sev-rep mod-sev-reps mod/default-rules)
    :action)
  "hide")

;; ── strictest-sol helper ──

(mod-sev-test!
  "strictest-sol picks max severity"
  (dict-get
    (mod/strictest-sol (list {:Action "keep" :Rule "k"} {:Action "remove" :Rule "r"} {:Action "hide" :Rule "h"}))
    "Action")
  "remove")
(mod-sev-test! "strictest-sol nil for empty" (mod/strictest-sol (list)) nil)

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