;; Pretext island — effect as let binding
(defisland
  ()
  (let
    ((words (split "In the beginning was the Word, and the Word was with God, and the Word was God. The same was in the beginning with God. All things were made by him; and without him was not any thing made that was made. In him was life; and the life was the light of men." " "))
      (mxw (signal 500))
      (font-size (signal 16))
      (use-optimal (signal true))
      (doc (host-global "document"))
      (canvas (host-call doc "createElement" "canvas"))
      (ctx (host-call canvas "getContext" "2d"))
      (el-ref (signal nil))
      (_eff
        (effect
          (fn
            ()
            (let
              ((el (deref el-ref))
                (w (deref mxw))
                (sz (deref font-size))
                (opt (deref use-optimal)))
              (when
                el
                (host-set!
                  ctx
                  "font"
                  (str sz "px 'Pretext Serif', DejaVu Serif, serif"))
                (let
                  ((lh (* sz 1.5))
                    (widths
                      (map
                        (fn
                          (wd)
                          (host-get (host-call ctx "measureText" wd) "width"))
                        words))
                    (spw
                      (host-get (host-call ctx "measureText" " ") "width")))
                  (let
                    ((ranges (if opt (break-lines widths spw w) (break-lines-greedy widths spw w))))
                    (let
                      ((lines (pretext-layout-lines words widths ranges spw w lh))
                        (info (host-call doc "createElement" "div"))
                        (container (host-call doc "createElement" "div")))
                      (host-set! el "innerHTML" "")
                      (host-set! info "className" "px-4 pt-3 pb-1")
                      (host-set!
                        info
                        "innerHTML"
                        (str
                          "<span class='text-xs font-medium uppercase tracking-wide text-stone-400'>"
                          (len lines)
                          " lines — "
                          w
                          "px / "
                          sz
                          "px / "
                          (if opt "optimal" "greedy")
                          "</span>"))
                      (host-call el "appendChild" info)
                      (host-set!
                        container
                        "style"
                        (str
                          "position:relative;height:"
                          (+ (* (len lines) lh) 24)
                          "px;padding:12px 16px"))
                      (let
                        rl
                        ((li 0))
                        (when
                          (< li (len lines))
                          (let
                            ((line (nth lines li))
                              (wds (get (nth lines li) :words)))
                            (let
                              rw
                              ((wi 0))
                              (when
                                (< wi (len wds))
                                (let
                                  ((pw (nth wds wi))
                                    (span
                                      (host-call doc "createElement" "span")))
                                  (host-set!
                                    span
                                    "textContent"
                                    (get pw :word))
                                  (host-set!
                                    span
                                    "style"
                                    (str
                                      "position:absolute;left:"
                                      (+ (get pw :x) 16)
                                      "px;top:"
                                      (+ (get line :y) 12)
                                      "px;font:"
                                      sz
                                      "px 'Pretext Serif',serif;white-space:nowrap"))
                                  (host-call container "appendChild" span)
                                  (rw (+ wi 1))))))
                          (rl (+ li 1))))
                      (host-call el "appendChild" container))))))))))
    (div
      (~tw :tokens "space-y-4")
      (div
        (~tw :tokens "flex flex-wrap gap-4 items-end")
        (div
          (label (~tw :tokens "block text-xs text-stone-500 mb-1") "Width")
          (input
            :type "range"
            :min "200"
            :max "700"
            :value (deref mxw)
            (~tw :tokens "w-32")
            :on-input (fn
              (e)
              (reset!
                mxw
                (parse-number (host-get (host-get e "target") "value"))))))
        (div
          (label
            (~tw :tokens "block text-xs text-stone-500 mb-1")
            "Font size")
          (input
            :type "range"
            :min "10"
            :max "24"
            :value (deref font-size)
            (~tw :tokens "w-24")
            :on-input (fn
              (e)
              (reset!
                font-size
                (parse-number (host-get (host-get e "target") "value"))))))
        (div
          (label
            (~tw :tokens "block text-xs text-stone-500 mb-1")
            "Algorithm")
          (button
            (~tw :tokens "px-3 py-1 rounded border text-sm")
            :on-click (fn (e) (reset! use-optimal (not (deref use-optimal))))
            (if (deref use-optimal) "Knuth-Plass" "Greedy"))))
      (div
        :class "rounded-lg border border-stone-200 bg-white"
        :ref (fn (el) (reset! el-ref el))
        ""))))