;; lib/events/tests/integration.sx — end-to-end pipeline: derive notification
;; messages (SX) -> deliver them through the durable notify flow (Scheme).

(define ev-it-pass 0)
(define ev-it-fail 0)
(define ev-it-failures (list))

(define
  ev-it-check!
  (fn
    (name got expected)
    (if
      (= got expected)
      (set! ev-it-pass (+ ev-it-pass 1))
      (do
        (set! ev-it-fail (+ ev-it-fail 1))
        (append!
          ev-it-failures
          (str name "\n    expected: " expected "\n    got:      " got))))))

(define ev-it-status (fn (outcome) (first outcome)))
(define ev-it-id (fn (outcome) (first (rest outcome))))

;; A store with a weekly class; nia + ola booked into the first occurrence.
(define
  ev-it-setup
  (fn
    (b)
    (let
      ((store (ev/schedule (ev/empty) (quote yoga) (ev-dt 2026 6 1 18 0) 60 {:freq :weekly :count 4 :byday (list 0 2)} 20)))
      (let
        ((occ1 (ev-occ (quote yoga) (ev-dt 2026 6 1 18 0) 60)))
        (do
          (ev/book-occ! b store (quote nia) occ1)
          (ev/book-occ! b store (quote ola) occ1)
          store)))))

(define
  ev-it-run-all!
  (fn
    ()
    (do
      (let
        ((b (persist/open)))
        (let
          ((store (ev-it-setup b)))
          (let
            ((reminders (ev/agenda-reminders b store (ev-date 2026 6 1) (ev-date 2026 7 1) 60)))
            (let
              ((msgs (map ev/reminder->msg reminders))
                (outcomes
                  (ev/deliver-messages
                    (map ev/reminder->msg reminders)
                    ev-notify-ok-transport
                    3
                    20)))
              (do
                (ev-it-check!
                  "every booked attendee's reminder is delivered"
                  (map ev-it-status outcomes)
                  (list "delivered" "delivered"))
                (ev-it-check!
                  "one delivery per derived reminder"
                  (len outcomes)
                  (len msgs))
                (ev-it-check!
                  "delivered ids match the reminder idempotency keys"
                  (map ev-it-id outcomes)
                  (map (fn (r) (get r :id)) reminders)))))))
      (let
        ((b (persist/open)))
        (let
          ((store (ev-it-setup b)))
          (let
            ((msgs (map ev/reminder->msg (ev/agenda-reminders b store (ev-date 2026 6 1) (ev-date 2026 7 1) 60))))
            (ev-it-check!
              "a permanently-failing transport reports failed deliveries"
              (map
                ev-it-status
                (ev/deliver-messages
                  msgs
                  "(lambda (k p) (list (quote retry) (quote down)))"
                  2
                  20))
              (list "failed" "failed")))))
      (let
        ((b (persist/open)))
        (do
          (ev/book! b "occ" 1 (quote nia))
          (ev/waitlist! b "occ" 1 (quote ola))
          (ev/cancel-promote! b "occ" 1 (quote nia))
          (let
            ((promoted (ev/notify-of-kind (ev/booking-notifications b "occ" (quote yoga)) :promoted)))
            (let
              ((outcomes (ev/deliver-messages (map ev/booking-notify->msg promoted) ev-notify-ok-transport 3 12)))
              (do
                (ev-it-check!
                  "the waitlist-promotion notification is delivered"
                  (map ev-it-status outcomes)
                  (list "delivered"))
                (ev-it-check!
                  "exactly one promotion was delivered"
                  (len outcomes)
                  1))))))
      (let
        ((b (persist/open)))
        (let
          ((ev (ev-event (quote yoga) (ev-dt 2026 6 1 18 0) 60 {:freq :daily :count 3} 20)))
          (do
            (ev/book-occ!
              b
              (ev/add-event (ev/empty) ev)
              (quote nia)
              (ev-occ
                (quote yoga)
                (ev-dt 2026 6 2 18 0)
                60))
            (let
              ((moved (ev-with-override ev (ev-dt 2026 6 2 18 0) (ev-dt 2026 6 2 20 0) 60)))
              (let
                ((outcomes (ev/deliver-messages (map ev/reschedule-notify->msg (ev/reschedule-notifications b moved)) ev-notify-ok-transport 3 12)))
                (ev-it-check!
                  "the reschedule notice is delivered to the booked attendee"
                  (map ev-it-status outcomes)
                  (list "delivered")))))))
      (ev-it-check!
        "delivering no messages yields no outcomes"
        (ev/deliver-messages
          (list)
          ev-notify-ok-transport
          3
          12)
        (list)))))

(define
  ev-integration-tests-run!
  (fn
    ()
    (do
      (set! ev-it-pass 0)
      (set! ev-it-fail 0)
      (set! ev-it-failures (list))
      (ev-it-run-all!)
      {:failures ev-it-failures :total (+ ev-it-pass ev-it-fail) :passed ev-it-pass :failed ev-it-fail})))
