(defisland
  (&key initial-expr)
  (let
    ((source (signal (or initial-expr "(+ 1 (* 2 3))")))
      (state (signal nil))
      (steps (signal 0))
      (history (signal (list)))
      (error-msg (signal nil)))
    (define
      start-eval
      (fn
        ()
        (reset! error-msg nil)
        (reset! history (list))
        (reset! steps 0)
        (let
          ((parsed (sx-parse (deref source))))
          (if
            (empty? parsed)
            (reset! error-msg "Parse error: empty expression")
            (reset!
              state
              (make-cek-state (first parsed) (make-env) (list)))))))
    (define
      do-step
      (fn
        ()
        (when
          (and (deref state) (not (cek-terminal? (deref state))))
          (let
            ((prev (deref state)))
            (swap! history (fn (h) (append h (list prev))))
            (swap! steps inc)
            (reset! state (cek-step prev))))))
    (define
      do-run
      (fn
        ()
        (when
          (deref state)
          (let
            run-loop
            ((n 0))
            (when
              (and (not (cek-terminal? (deref state))) (< n 200))
              (do-step)
              (run-loop (+ n 1)))))))
    (define
      do-reset
      (fn
        ()
        (reset! state nil)
        (reset! steps 0)
        (reset! history (list))
        (reset! error-msg nil)))
    (define
      fmt-control
      (fn
        (s)
        (if
          (nil? s)
          "—"
          (let
            ((c (get s "control")))
            (if (nil? c) "—" (sx-serialize c))))))
    (define
      fmt-value
      (fn
        (s)
        (if
          (nil? s)
          "—"
          (let
            ((v (get s "value")))
            (cond
              (nil? v)
              "nil"
              (callable? v)
              (str "λ:" (or (lambda-name v) "fn"))
              :else (sx-serialize v))))))
    (define
      fmt-kont
      (fn
        (s)
        (if
          (nil? s)
          "—"
          (let
            ((k (get s "kont")))
            (if
              (empty? k)
              "[]"
              (str "[" (join " " (map (fn (f) (get f "type")) k)) "]"))))))
    (start-eval)
    (div
      (~tw :tokens "space-y-4")
      (div
        (~tw :tokens "flex gap-2 items-end")
        (div
          (~tw :tokens "flex-1")
          (label (~tw :tokens "text-xs text-stone-400 block mb-1") "Expression")
          (input
            :type "text"
            :bind source
            (~tw :tokens "w-full px-3 py-1.5 rounded border border-stone-300 font-mono text-sm focus:outline-none focus:border-violet-400")
            :on-change (fn (e) (start-eval))))
        (div
          (~tw :tokens "flex gap-1")
          (button
            :on-click (fn (e) (start-eval))
            (~tw :tokens "px-3 py-1.5 rounded bg-stone-200 text-stone-700 text-sm hover:bg-stone-300")
            "Reset")
          (button
            :on-click (fn (e) (do-step))
            (~tw :tokens "px-3 py-1.5 rounded bg-violet-500 text-white text-sm hover:bg-violet-600")
            "Step")
          (button
            :on-click (fn (e) (do-run))
            (~tw :tokens "px-3 py-1.5 rounded bg-violet-700 text-white text-sm hover:bg-violet-800")
            "Run")))
      (when
        (deref error-msg)
        (div (~tw :tokens "text-red-600 text-sm") (deref error-msg)))
      (when
        (deref state)
        (div
          (~tw :tokens "rounded border border-stone-200 bg-white p-3 font-mono text-sm space-y-1")
          (div
            (~tw :tokens "flex gap-4")
            (span (~tw :tokens "text-stone-400 w-16") "Step")
            (span (~tw :tokens "font-bold") (deref steps)))
          (div
            (~tw :tokens "flex gap-4")
            (span (~tw :tokens "text-stone-400 w-16") "Phase")
            (span
              :class (str
                "font-bold "
                (if
                  (= (get (deref state) "phase") "eval")
                  "text-blue-600"
                  "text-green-600"))
              (get (deref state) "phase")))
          (div
            (~tw :tokens "flex gap-4")
            (span (~tw :tokens "text-violet-500 w-16") "C")
            (span (fmt-control (deref state))))
          (div
            (~tw :tokens "flex gap-4")
            (span (~tw :tokens "text-amber-600 w-16") "V")
            (span (fmt-value (deref state))))
          (div
            (~tw :tokens "flex gap-4")
            (span (~tw :tokens "text-emerald-600 w-16") "K")
            (span (fmt-kont (deref state))))
          (when
            (cek-terminal? (deref state))
            (div
              (~tw :tokens "mt-2 pt-2 border-t border-stone-200 text-stone-800 font-bold")
              (str "Result: " (sx-serialize (cek-value (deref state))))))))
      (when
        (not (empty? (deref history)))
        (div
          (~tw :tokens "rounded border border-stone-100 bg-stone-50 p-2")
          (div (~tw :tokens "text-xs text-stone-400 mb-1") "History")
          (div
            (~tw :tokens "space-y-0.5 font-mono text-xs max-h-48 overflow-y-auto")
            (map-indexed
              (fn
                (i s)
                (div
                  (~tw :tokens "flex gap-2 text-stone-500")
                  (span (~tw :tokens "text-stone-300 w-6 text-right") (+ i 1))
                  (span
                    :class (if
                      (= (get s "phase") "eval")
                      "text-blue-400"
                      "text-green-400")
                    (get s "phase"))
                  (span (~tw :tokens "text-violet-400 truncate") (fmt-control s))
                  (span (~tw :tokens "text-amber-400") (fmt-value s))
                  (span (~tw :tokens "text-emerald-400") (fmt-kont s))))
              (deref history))))))))
