;; N-way weighted blend effect
;; Streaming-compatible: pass inputs as a list of frames
;; Usage: (blend_multi :inputs [(read a) (read b) (read c)] :weights [0.3 0.4 0.3])
;;
;; Parameters:
;;   inputs      - list of N frames to blend
;;   weights     - list of N floats, one per input (resolved per-frame)
;;   mode        - blend mode applied when folding each frame in:
;;                   "alpha"       — pure weighted average (default)
;;                   "multiply"    — darken by multiplication
;;                   "screen"      — lighten (inverse multiply)
;;                   "overlay"     — contrast-boosting midtone blend
;;                   "soft-light"  — gentle dodge/burn
;;                   "hard-light"  — strong dodge/burn
;;                   "color-dodge" — brightens towards white
;;                   "color-burn"  — darkens towards black
;;                   "difference"  — absolute pixel difference
;;                   "exclusion"   — softer difference
;;                   "add"         — additive (clamped)
;;                   "subtract"    — subtractive (clamped)
;;                   "darken"      — per-pixel minimum
;;                   "lighten"     — per-pixel maximum
;;   resize_mode - how to match frame dimensions (fit, crop, stretch)
;;
;; Uses a left-fold over inputs[1..N-1].  At each step the running
;; opacity is:  w[i] / (w[0] + w[1] + ... + w[i])
;; which produces the correct normalised weighted result.

(require-primitives "image" "blending")

(define-effect blend_multi
  :params (
    (inputs :type list :default [])
    (weights :type list :default [])
    (mode :type string :default "alpha")
    (resize_mode :type string :default "fit")
  )
  (let [n (len inputs)
        ;; Target dimensions from first frame
        target-w (image:width (nth inputs 0))
        target-h (image:height (nth inputs 0))
        ;; Fold over indices 1..n-1
        ;; Accumulator is (list blended-frame running-weight-sum)
        seed (list (nth inputs 0) (nth weights 0))
        result (reduce (range 1 n) seed
                 (lambda (pair i)
                   (let [acc (nth pair 0)
                         running (nth pair 1)
                         w (nth weights i)
                         new-running (+ running w)
                         opacity (/ w (max new-running 0.001))
                         f (image:resize (nth inputs i) target-w target-h "linear")
                         ;; Apply blend mode then mix with opacity
                         blended (if (= mode "alpha")
                                   (blending:blend-images acc f opacity)
                                   (blending:blend-images acc (blending:blend-mode acc f mode) opacity))]
                     (list blended new-running))))]
    (nth result 0)))
