;; _hyperscript runtime tests
;; Pure function tests run directly; DOM-dependent shims tested via Playwright.

;; ── Type coercion ─────────────────────────────────────────────
(defsuite
  "hs-runtime-coerce"
  (deftest "coerce string to Int" (assert= 42 (hs-coerce "42" "Int")))
  (deftest
    "coerce string to Float"
    (assert= 3.14 (hs-coerce "3.14" "Float")))
  (deftest "coerce number to String" (assert= "42" (hs-coerce 42 "String")))
  (deftest "coerce truthy to Boolean" (assert= true (hs-coerce 1 "Boolean")))
  (deftest
    "coerce falsy to Boolean"
    (assert= false (hs-coerce nil "Boolean")))
  (deftest
    "coerce value to Array wraps"
    (let
      ((result (hs-coerce 5 "Array")))
      (assert= true (list? result))
      (assert= 5 (first result))))
  (deftest
    "coerce list to Array passes through"
    (let
      ((result (hs-coerce (list 1 2) "Array")))
      (assert= 2 (len result))))
  (deftest
    "unknown type passes through"
    (assert= "hello" (hs-coerce "hello" "Foo"))))

;; ── Object creation ───────────────────────────────────────────
(defsuite
  "hs-runtime-make"
  (deftest
    "make Object returns dict"
    (let ((obj (hs-make "Object"))) (assert= true (dict? obj))))
  (deftest
    "make Array returns list"
    (let
      ((arr (hs-make "Array")))
      (assert= true (list? arr))
      (assert= 0 (len arr))))
  (deftest
    "make Set returns list"
    (let ((s (hs-make "Set"))) (assert= true (list? s))))
  (deftest
    "make Map returns dict"
    (let ((m (hs-make "Map"))) (assert= true (dict? m)))))

;; ── Iteration ─────────────────────────────────────────────────
(defsuite
  "hs-runtime-repeat"
  (deftest
    "repeat-times calls thunk N times"
    (let
      ((count 0))
      (hs-repeat-times 5 (fn () (set! count (+ count 1))))
      (assert= 5 count)))
  (deftest
    "repeat-times zero does nothing"
    (let
      ((count 0))
      (hs-repeat-times 0 (fn () (set! count (+ count 1))))
      (assert= 0 count)))
  (deftest
    "repeat-times one"
    (let
      ((count 0))
      (hs-repeat-times 1 (fn () (set! count (+ count 1))))
      (assert= 1 count))))

;; ── Init ──────────────────────────────────────────────────────
(defsuite
  "hs-runtime-init"
  (deftest
    "init calls thunk"
    (let
      ((called false))
      (hs-init (fn () (set! called true)))
      (assert= true called))))

;; ── End-to-end pipeline ───────────────────────────────────────
(defsuite
  "hs-runtime-e2e"
  (deftest
    "source → SX shape: add class"
    (let
      ((sx (hs-to-sx-from-source "add .active to me")))
      (assert= (quote dom-add-class) (first sx))
      (assert= 3 (len sx))))
  (deftest
    "source → SX shape: sequence"
    (let
      ((sx (hs-to-sx-from-source "add .a to me then add .b to me")))
      (assert= (quote do) (first sx))
      (assert= 3 (len sx))))
  (deftest
    "source → SX shape: on handler"
    (let
      ((sx (hs-to-sx-from-source "on click log 'hi' end")))
      (assert= (quote hs-on) (first sx))
      (assert= (quote me) (nth sx 1))
      (assert= "click" (nth sx 2))))
  (deftest
    "source → SX shape: if-else"
    (let
      ((sx (hs-to-sx-from-source "if true log 1 else log 0 end")))
      (assert= (quote if) (first sx))))
  (deftest
    "source → SX shape: set variable"
    (let
      ((sx (hs-to-sx-from-source "set x to 42")))
      (assert= (quote set!) (first sx))
      (assert= (quote x) (nth sx 1))
      (assert= 42 (nth sx 2))))
  (deftest
    "source → SX shape: fetch"
    (let
      ((sx (hs-to-sx-from-source "fetch '/api'")))
      (assert= (quote hs-fetch) (first sx))
      (assert= "text" (nth sx 2))))
  (deftest
    "source → SX shape: def function"
    (let
      ((sx (hs-to-sx-from-source "def add(a, b) return a end")))
      (assert= (quote define) (first sx))
      (assert= (quote add) (nth sx 1))
      (assert= (quote fn) (first (nth sx 2))))))

(defsuite
  "hs-handler-extensions"
  (deftest
    "render compiles to render-to-html"
    (let
      ((sx (hs-to-sx-from-source "render ~badge :label 'New'")))
      (assert= (quote render-to-html) (first sx))
      (assert= (quote ~badge) (nth sx 1))))
  (deftest
    "eval inlines SX with variable access"
    (let
      ((h (hs-handler "set x to 10 then set y to eval (+ x 5)")))
      (h "el")
      (assert= 15 y)))
  (deftest
    "eval as command in handler"
    (let ((h (hs-handler "eval (set! z 99)"))) (h "el") (assert= 99 z))))