;; lib/mod/tests/whatif.sx — Ext 10: policy what-if / impact analysis.

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

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

;; rules-b is the default policy with spam-hide removed: spam now falls through
;; to default-keep. A spam report flips hide → keep; everything else is unchanged.
(define mod-wi-rules-a mod/default-rules)
(define
  mod-wi-rules-b
  (list
    (mod/mk-rule
      "reviewer-remove"
      :remove (list (list :evidence "confirmed-abuse")))
    (mod/mk-rule
      "abuse-remove"
      :remove (list (list :classification "abuse")))
    (mod/mk-rule
      "repeated-escalate"
      :escalate (list (list :count-at-least 3)))
    (mod/mk-rule "default-keep" :keep (list))))

(define mod-wi-spam (mod/mk-report "r1" "a" "bob" "this is spam"))
(define mod-wi-abuse (mod/mk-report "r2" "a" "carol" "harassment here"))
(define mod-wi-clean (mod/mk-report "r3" "a" "dave" "a fine post"))

;; ── single-report diff ──

(define
  mod-wi-d
  (mod/decision-diff
    mod-wi-spam
    (list mod-wi-spam)
    mod-wi-rules-a
    mod-wi-rules-b))
(mod-wi-test! "spam before = hide" (get mod-wi-d :before) "hide")
(mod-wi-test! "spam after = keep" (get mod-wi-d :after) "keep")
(mod-wi-test! "spam decision flips" (get mod-wi-d :changed) true)
(mod-wi-test! "diff carries report id" (get mod-wi-d :report-id) "r1")

(define
  mod-wi-da
  (mod/decision-diff
    mod-wi-abuse
    (list mod-wi-abuse)
    mod-wi-rules-a
    mod-wi-rules-b))
(mod-wi-test! "abuse unchanged (remove both)" (get mod-wi-da :changed) false)
(mod-wi-test! "abuse stays remove" (get mod-wi-da :after) "remove")

(define
  mod-wi-dc
  (mod/decision-diff
    mod-wi-clean
    (list mod-wi-clean)
    mod-wi-rules-a
    mod-wi-rules-b))
(mod-wi-test! "clean unchanged (keep both)" (get mod-wi-dc :changed) false)

;; ── batch impact ──

(define mod-wi-batch (list mod-wi-spam mod-wi-abuse mod-wi-clean))
(define
  mod-wi-impact
  (mod/policy-impact mod-wi-batch mod-wi-rules-a mod-wi-rules-b))

(mod-wi-test!
  "impact lists only changed reports"
  (len mod-wi-impact)
  1)
(mod-wi-test!
  "impacted report is the spam one"
  (get (first mod-wi-impact) :report-id)
  "r1")
(mod-wi-test!
  "impact-count agrees"
  (mod/impact-count mod-wi-batch mod-wi-rules-a mod-wi-rules-b)
  1)

;; ── identical rule sets → no impact ──

(mod-wi-test!
  "same rules → zero impact"
  (mod/impact-count mod-wi-batch mod-wi-rules-a mod-wi-rules-a)
  0)
(mod-wi-test!
  "same rules → empty report"
  (mod/impact-report mod-wi-batch mod-wi-rules-a mod-wi-rules-a)
  "No decisions change.")

;; ── rendering ──

(mod-wi-test!
  "impact-report renders the flip"
  (mod/str-contains?
    (mod/impact-report mod-wi-batch mod-wi-rules-a mod-wi-rules-b)
    "r1: hide → keep")
  true)

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