;; lib/commerce/tests/recon.sx — reconciliation as relational ledger queries.
;; Uses (commerce-test name got expected) provided by conformance.sh.

(define q1 {:codes (list) :subtotal 1000 :discount 0 :total 1200 :tax 200})

(define b (persist/mem-backend))

;; OK1 — clean payment
(define _ok (order-create b "OK1" 1 q1))
(define _okp (order-pay b "OK1" "ok-ref" 2 1200))

;; OVER1 — double charge under two different refs
(define _ov (order-create b "OVER1" 1 q1))
(define _ova (order-pay b "OVER1" "ov-a" 2 1200))
(define _ovb (order-pay b "OVER1" "ov-b" 3 1200))

;; UNDER1 — short payment
(define _un (order-create b "UNDER1" 1 q1))
(define _unp (order-pay b "UNDER1" "un-ref" 2 900))

;; PART1 — paid in full, then partially refunded
(define _pa (order-create b "PART1" 1 q1))
(define _pap (order-pay b "PART1" "pa-ref" 2 1200))
(define _par (order-refund b "PART1" "pa-rf" 3 200))

;; REPLAY1 — webhook fires twice with the same ref (idempotent)
(define _rp (order-create b "REPLAY1" 1 q1))
(define _rpa (order-pay b "REPLAY1" "rp-ref" 2 1200))
(define _rpb (order-pay b "REPLAY1" "rp-ref" 2 1200))

;; PEND1 — created, not yet paid
(define _pe (order-create b "PEND1" 1 q1))

;; --- summaries ---

(commerce-test "summary-count" (len (ledger-summaries b)) 6)
(commerce-test
  "summary-ok1"
  (order-summary b "order/OK1")
  (list "order/OK1" 1200 1200 0 1200 :ok))
(commerce-test
  "summary-part1"
  (order-summary b "order/PART1")
  (list "order/PART1" 1200 1200 200 1000 :underpaid))

;; --- forward status query ---

(commerce-test
  "status-forward-ok"
  (run* st (recon-statuso (ledger-summaries b) "order/OK1" st))
  (list :ok))

;; --- backward status queries (the showcase) ---

(commerce-test
  "settled"
  (sort (settled-orders b))
  (sort (list "order/OK1" "order/REPLAY1")))
(commerce-test "overpaid" (overpaid-orders b) (list "order/OVER1"))
(commerce-test
  "underpaid"
  (sort (underpaid-orders b))
  (sort (list "order/UNDER1" "order/PART1")))
(commerce-test "unpaid" (unpaid-orders b) (list "order/PEND1"))
(commerce-test
  "mismatched"
  (sort (mismatched-orders b))
  (sort (list "order/OVER1" "order/UNDER1" "order/PART1")))

;; --- backward net-amount query ---

(commerce-test
  "net-1200"
  (sort (orders-with-net b 1200))
  (sort (list "order/OK1" "order/REPLAY1")))
(commerce-test
  "net-2400"
  (orders-with-net b 2400)
  (list "order/OVER1"))
(commerce-test
  "net-900"
  (orders-with-net b 900)
  (list "order/UNDER1"))

;; --- discrepancy: +1200 (over) - 300 (under) - 200 (refund) = 700 ---

(commerce-test "discrepancy" (ledger-discrepancy b) 700)

;; --- double-charge guard ---

(commerce-test "double-charge-detected" (order-recon b "OVER1") :overpaid)
(commerce-test "double-charge-amount" (order-paid b "OVER1") 2400)

;; --- partial refund ---

(commerce-test "partial-refund-net" (order-recon b "PART1") :underpaid)
(commerce-test
  "partial-refund-amount"
  (order-refunded-amount-of (order-events b "PART1"))
  200)

;; --- webhook replay: same ref twice records once ---

(commerce-test
  "replay-single-event"
  (len (order-events b "REPLAY1"))
  2)
(commerce-test "replay-paid-once" (order-paid b "REPLAY1") 1200)
(commerce-test "replay-settled" (order-recon b "REPLAY1") :ok)
