;; lib/mod/api.sx — report registry + lifecycle façade + public entry points.
;;
;; mod/report files a report (assigning a sequential id) and opens a lifecycle
;; case for it; mod/add-evidence accumulates evidence; mod/decide runs the engine
;; and commits to the audit log. The lifecycle façade (mod/triage, mod/resolve,
;; mod/review, mod/appeal, mod/finalize) drives the per-report case through its
;; states, logging each committed decision to the audit trail.

(define mod/*reports* (list))
(define mod/*cases* (list))
(define mod/*counter* 0)
(define mod/*rules* mod/default-rules)

(define
  mod/reset!
  (fn
    ()
    (begin
      (set! mod/*reports* (list))
      (set! mod/*cases* (list))
      (set! mod/*counter* 0)
      (mod/audit-reset!))))

(define
  mod/report
  (fn
    (by about reason)
    (begin
      (set! mod/*counter* (+ mod/*counter* 1))
      (let
        ((id (str "r" mod/*counter*)))
        (let
          ((r (mod/mk-report id by about reason)))
          (begin
            (append! mod/*reports* r)
            (append! mod/*cases* {:id id :case (mod/mk-case r)})
            r))))))

(define
  mod/get-report
  (fn
    (id)
    (reduce
      (fn (acc r) (if (= (mod/report-id r) id) r acc))
      nil
      mod/*reports*)))

(define
  mod/add-evidence
  (fn
    (id kind val)
    (let
      ((r (mod/get-report id)))
      (if
        (nil? r)
        nil
        (let
          ((updated (mod/attach-evidence r (mod/mk-evidence kind val))))
          (begin
            (set!
              mod/*reports*
              (map
                (fn (x) (if (= (mod/report-id x) id) updated x))
                mod/*reports*))
            updated))))))

(define
  mod/decide
  (fn
    (id)
    (let
      ((r (mod/get-report id)))
      (if
        (nil? r)
        nil
        (let
          ((d (mod/decide-report r mod/*reports* mod/*rules*)))
          (begin (mod/log-decision! d (mod/report-evidence r)) d))))))

;; ── lifecycle façade over the case registry ──

(define
  mod/case-of
  (fn
    (id)
    (reduce
      (fn (acc rec) (if (= (get rec :id) id) (get rec :case) acc))
      nil
      mod/*cases*)))

(define
  mod/case-store!
  (fn
    (id c)
    (set!
      mod/*cases*
      (map
        (fn (rec) (if (= (get rec :id) id) {:id id :case c} rec))
        mod/*cases*))))

;; apply a lifecycle op to the stored case, persist it, and (when a decision was
;; committed cleanly) append it to the audit log; returns the updated case
(define
  mod/case-apply!
  (fn
    (id op log?)
    (let
      ((c (mod/case-of id)))
      (if
        (nil? c)
        nil
        (let
          ((c2 (op c)))
          (begin
            (mod/case-store! id c2)
            (when
              log?
              (when
                (nil? (mod/case-error c2))
                (let
                  ((d (mod/case-decision c2)))
                  (if
                    (nil? d)
                    nil
                    (mod/log-decision!
                      d
                      (mod/report-evidence (mod/case-report c2)))))))
            c2))))))

(define
  mod/triage
  (fn
    (id)
    (mod/case-apply!
      id
      (fn (c) (mod/case-triage c mod/*reports* mod/*rules*))
      false)))

(define
  mod/resolve
  (fn (id) (mod/case-apply! id (fn (c) (mod/case-resolve c)) true)))

(define
  mod/review
  (fn
    (id kind val)
    (mod/case-apply!
      id
      (fn (c) (mod/case-review c kind val mod/*reports* mod/*rules*))
      true)))

(define
  mod/appeal
  (fn
    (id kind val)
    (mod/case-apply!
      id
      (fn (c) (mod/case-appeal c kind val mod/*reports* mod/*rules*))
      true)))

(define
  mod/finalize
  (fn (id) (mod/case-apply! id (fn (c) (mod/case-finalize c)) false)))
