;; lib/mod/tests/defrule.sx — Ext 18: ergonomic defrule / ruleset.

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

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

;; ── defrule produces the same structure as mk-rule ──

(define
  mod-dr-r
  (mod/defrule "spam-hide" :hide (list :classification "spam")))
(mod-dr-test! "defrule name" (mod/rule-name mod-dr-r) "spam-hide")
(mod-dr-test! "defrule action" (mod/rule-action mod-dr-r) "hide")
(mod-dr-test!
  "defrule when wraps the conditions"
  (mod/rule-when mod-dr-r)
  (list (list :classification "spam")))
(mod-dr-test!
  "defrule equals mk-rule equivalent"
  (mod/rule-when mod-dr-r)
  (mod/rule-when
    (mod/mk-rule "spam-hide" :hide (list (list :classification "spam")))))

;; ── multi-condition + no-condition ──

(define
  mod-dr-multi
  (mod/defrule
    "strict"
    :hide (list :classification "spam")
    (list :not (list :attr "verified"))))
(mod-dr-test!
  "defrule collects multiple conditions"
  (len (mod/rule-when mod-dr-multi))
  2)

(define mod-dr-catch (mod/defrule "default-keep" :keep))
(mod-dr-test!
  "defrule with no conditions is unconditional"
  (mod/rule-when mod-dr-catch)
  (list))

;; ── ruleset assembles a list ──

(define
  mod-dr-rules
  (mod/ruleset
    (mod/defrule "spam-hide" :hide (list :classification "spam"))
    (mod/defrule "default-keep" :keep)))

(mod-dr-test! "ruleset length" (len mod-dr-rules) 2)
(mod-dr-test!
  "ruleset first rule name"
  (mod/rule-name (first mod-dr-rules))
  "spam-hide")

;; ── engine works with defrule/ruleset-built policy ──

(define mod-dr-spam (mod/mk-report "r1" "a" "b" "this is spam"))
(define mod-dr-clean (mod/mk-report "r2" "a" "b" "a fine post"))

(mod-dr-test!
  "defrule policy: spam → hide"
  (get
    (mod/decide-report mod-dr-spam (list mod-dr-spam) mod-dr-rules)
    :action)
  "hide")
(mod-dr-test!
  "defrule policy: clean → keep"
  (get
    (mod/decide-report mod-dr-clean (list mod-dr-clean) mod-dr-rules)
    :action)
  "keep")
(mod-dr-test!
  "defrule policy: spam names the rule"
  (get (mod/decide-report mod-dr-spam (list mod-dr-spam) mod-dr-rules) :rule)
  "spam-hide")

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