(defsuite
  "stepper-lib"
  (deftest
    "split-tag: string literal becomes leaf step"
    (let
      ((result (list)))
      (split-tag "hello" result)
      (assert-equal 1 (len result))
      (assert-equal "leaf" (get (first result) "type"))
      (assert-equal "hello" (get (first result) "expr"))))
  (deftest
    "split-tag: number literal becomes leaf step"
    (let
      ((result (list)))
      (split-tag 42 result)
      (assert-equal 1 (len result))
      (assert-equal "leaf" (get (first result) "type"))
      (assert-equal 42 (get (first result) "expr"))))
  (deftest
    "split-tag: empty list produces nothing"
    (let
      ((result (list)))
      (split-tag (list) result)
      (assert-equal 0 (len result))))
  (deftest
    "split-tag: simple div becomes open+close"
    (let
      ((result (list)) (parsed (sx-parse "(div)")))
      (split-tag (first parsed) result)
      (assert-equal 2 (len result))
      (assert-equal "open" (get (first result) "type"))
      (assert-equal "div" (get (first result) "tag"))
      (assert-equal "close" (get (nth result 1) "type"))))
  (deftest
    "split-tag: div with text child becomes open+leaf+close"
    (let
      ((result (list)) (parsed (sx-parse "(div \"hello\")")))
      (split-tag (first parsed) result)
      (assert-equal 3 (len result))
      (assert-equal "open" (get (first result) "type"))
      (assert-equal "leaf" (get (nth result 1) "type"))
      (assert-equal "hello" (get (nth result 1) "expr"))
      (assert-equal "close" (get (nth result 2) "type"))))
  (deftest
    "split-tag: keyword attrs captured in open step"
    (let
      ((result (list)) (parsed (sx-parse "(div :class \"foo\" \"text\")")))
      (split-tag (first parsed) result)
      (assert-equal 3 (len result))
      (assert-equal "open" (get (first result) "type"))
      (let
        ((attrs (get (first result) "attrs")))
        (assert-equal 2 (len attrs)))))
  (deftest
    "split-tag: nested tags produce nested open/close pairs"
    (let
      ((result (list)) (parsed (sx-parse "(div (span \"hi\"))")))
      (split-tag (first parsed) result)
      (assert-equal 5 (len result))
      (assert-equal "open" (get (first result) "type"))
      (assert-equal "div" (get (first result) "tag"))
      (assert-equal "open" (get (nth result 1) "type"))
      (assert-equal "span" (get (nth result 1) "tag"))
      (assert-equal "leaf" (get (nth result 2) "type"))
      (assert-equal "close" (get (nth result 3) "type"))
      (assert-equal "close" (get (nth result 4) "type"))))
  (deftest
    "split-tag: component call becomes expr step"
    (let
      ((result (list)) (parsed (sx-parse "(~my/comp :title \"hi\")")))
      (split-tag (first parsed) result)
      (assert-equal 1 (len result))
      (assert-equal "expr" (get (first result) "type"))))
  (deftest
    "split-tag: component inside div becomes spread"
    (let
      ((result (list))
        (parsed (sx-parse "(div (~cssx/tw :tokens \"foo\") \"text\")")))
      (split-tag (first parsed) result)
      (let
        ((open-step (first result)))
        (assert-equal "open" (get open-step "type"))
        (assert-equal 1 (len (get open-step "spreads"))))))
  (deftest
    "build-code-tokens: string expr produces quoted token"
    (let
      ((tokens (list)) (ref (dict "v" 0)))
      (build-code-tokens "hello" tokens ref 0)
      (assert-equal 1 (len tokens))
      (assert-equal "\"hello\"" (get (first tokens) "text"))
      (assert-equal "text-emerald-700" (get (first tokens) "cls"))
      (assert-equal 0 (get (first tokens) "step"))))
  (deftest
    "build-code-tokens: number expr produces token"
    (let
      ((tokens (list)) (ref (dict "v" 0)))
      (build-code-tokens 42 tokens ref 0)
      (assert-equal 1 (len tokens))
      (assert-equal "42" (get (first tokens) "text"))
      (assert-equal "text-amber-700" (get (first tokens) "cls"))))
  (deftest
    "build-code-tokens: symbol produces token with name"
    (let
      ((tokens (list)) (ref (dict "v" 0)))
      (build-code-tokens (make-symbol "foo") tokens ref 0)
      (assert-equal 1 (len tokens))
      (assert-equal "foo" (get (first tokens) "text"))
      (assert-equal "text-stone-700" (get (first tokens) "cls"))))
  (deftest
    "build-code-tokens: html tag symbol gets sky color"
    (let
      ((tokens (list)) (ref (dict "v" 0)))
      (build-code-tokens (make-symbol "div") tokens ref 0)
      (assert-equal "text-sky-700 font-semibold" (get (first tokens) "cls"))))
  (deftest
    "build-code-tokens: component symbol gets rose color"
    (let
      ((tokens (list)) (ref (dict "v" 0)))
      (build-code-tokens (make-symbol "~my/comp") tokens ref 0)
      (assert-equal "text-rose-600 font-semibold" (get (first tokens) "cls"))))
  (deftest
    "build-code-tokens: list produces open-paren + children + close-paren"
    (let
      ((tokens (list))
        (ref (dict "v" 0))
        (parsed (sx-parse "(div \"hi\")")))
      (build-code-tokens (first parsed) tokens ref 0)
      (assert-equal "(" (get (first tokens) "text"))
      (assert-equal ")" (get (last tokens) "text"))))
  (deftest
    "build-code-tokens: step counter increments for strings"
    (let
      ((tokens (list)) (ref (dict "v" 5)))
      (build-code-tokens "hello" tokens ref 0)
      (assert-equal 5 (get (first tokens) "step"))
      (assert-equal 6 (get ref "v"))))
  (deftest
    "steps-to-preview: empty steps returns nil"
    (assert-equal nil (steps-to-preview (list) 5)))
  (deftest
    "steps-to-preview: target 0 returns nil"
    (let
      ((result (list)))
      (split-tag "hello" result)
      (assert-equal nil (steps-to-preview result 0))))
  (deftest
    "steps-to-preview: single leaf step reconstructs value"
    (let
      ((result (list)))
      (split-tag "hello" result)
      (assert-equal "hello" (steps-to-preview result 1))))
  (deftest
    "steps-to-preview: open+close reconstructs empty tag"
    (let
      ((result (list)) (parsed (sx-parse "(div)")))
      (split-tag (first parsed) result)
      (let
        ((preview (steps-to-preview result 2)))
        (assert-equal "div" (symbol-name (first preview))))))
  (deftest
    "steps-to-preview: partial steps build partial tree"
    (let
      ((result (list)) (parsed (sx-parse "(div (span \"a\") (span \"b\"))")))
      (split-tag (first parsed) result)
      (let
        ((preview (steps-to-preview result 4)))
        (assert-equal "div" (symbol-name (first preview)))
        (assert-equal true (> (len preview) 1)))))
  (deftest
    "steps-to-preview: full steps build complete tree"
    (let
      ((result (list)) (parsed (sx-parse "(div \"hello\")")))
      (split-tag (first parsed) result)
      (let
        ((preview (steps-to-preview result (len result))))
        (assert-equal "div" (symbol-name (first preview)))
        (assert-equal "hello" (nth preview 1))))))

(deftest
  "split-tag result is a render leak (list of dicts)"
  (let
    ((result (list)) (parsed (sx-parse "(div \"hello\")")))
    (split-tag (first parsed) result)
    (assert-equal true (is-render-leak? result))
    (assert-equal true (> (len result) 0))
    (assert-equal true (dict? (first result)))))
