;; ---------------------------------------------------------------------------
;; Client-side island — runs spec functions in the browser on button click
;; ---------------------------------------------------------------------------
(defisland (&key sf-source attr-detail req-attrs attr-keys)
  (let ((results (signal nil))
        (running (signal false))
        (run-demo (fn (e)
          (reset! running true)
          (let* ((t0 (now-ms))

                 ;; 1. categorize-special-forms
                 (t1 (now-ms))
                 (sf-exprs (sx-parse sf-source))
                 (sf-result (categorize-special-forms sf-exprs))
                 (sf-ms (- (now-ms) t1))
                 (sf-cats {})
                 (sf-total 0)
                 ;; 2. build-reference-data
                 (t2 (now-ms))
                 (ref-result (build-reference-data "attributes"
                   {"req-attrs" req-attrs "beh-attrs" (list) "uniq-attrs" (list)}
                   attr-keys))
                 (ref-ms (- (now-ms) t2))
                 (ref-sample (slice (or (get ref-result "req-attrs") (list)) 0 3))

                 ;; 3. build-attr-detail
                 (t3 (now-ms))
                 (attr-result (build-attr-detail "sx-get" attr-detail))
                 (attr-ms (- (now-ms) t3))

                 ;; 4. build-component-source
                 (t4 (now-ms))
                 (comp-result (build-component-source
                   {"type" "component" "name" "~demo-card"
                    "params" (list "title" "subtitle")
                    "has-children" true
                    "body-sx" "(div :class \"card\"\n  (h2 title)\n  (when subtitle (p subtitle))\n  children)"
                    "affinity" "auto"}))
                 (comp-ms (- (now-ms) t4))

                 ;; 5. build-routing-analysis
                 (t5 (now-ms))
                 (routing-result (build-routing-analysis (list
                   {"name" "home" "path" "/" "has-data" false "content-src" "(~home-content)"}
                   {"name" "dashboard" "path" "/dash" "has-data" true "content-src" "(~dashboard)"}
                   {"name" "about" "path" "/about" "has-data" false "content-src" "(~about-content)"}
                   {"name" "settings" "path" "/settings" "has-data" true "content-src" "(~settings)"})))
                 (routing-ms (- (now-ms) t5))

                 (total-ms (- (now-ms) t0)))

            ;; Post-process sf-result: count forms per category
            (for-each (fn (k)
              (dict-set! sf-cats k (len (get sf-result k))))
              (keys sf-result))

            (reset! results
              {"sf-cats" sf-cats
               "sf-total" (reduce (fn (acc k) (+ acc (get sf-cats k))) 0 (keys sf-cats))
               "sf-ms" sf-ms
               "ref-sample" ref-sample "ref-ms" ref-ms
               "attr-result" attr-result "attr-ms" attr-ms
               "comp-result" comp-result "comp-ms" comp-ms
               "routing-result" routing-result "routing-ms" routing-ms
               "total-ms" total-ms})))))

    (<>
      (button
        :class (if (deref running)
          "px-4 py-2 rounded-md bg-blue-600 text-white font-medium text-sm cursor-default mb-4"
          "px-4 py-2 rounded-md bg-violet-600 text-white font-medium text-sm hover:bg-violet-700 transition-colors mb-4")
        :on-click run-demo
        (if (deref running)
          (str "Done (" (get (deref results) "total-ms") "ms total)")
          "Run in Browser"))

      (when (deref results)
        (let ((r (deref results)))
          (div (~tw :tokens "grid grid-cols-1 md:grid-cols-2 gap-4")

            (~page-helpers-demo/demo-result-card
              :title "categorize-special-forms"
              :ms (get r "sf-ms") :theme "blue"
              :desc "Parses special-forms.sx and classifies each form by category (control flow, binding, quoting, etc)."
              (p (~tw :tokens "text-sm mb-1")
                (str (get r "sf-total") " forms in "
                     (len (keys (get r "sf-cats"))) " categories"))
              (map (fn (k)
                (div (str k ": " (get (get r "sf-cats") k))))
                (keys (get r "sf-cats"))))

            (~page-helpers-demo/demo-result-card
              :title "build-reference-data"
              :ms (get r "ref-ms") :theme "blue"
              :desc "Takes raw attribute tuples and generates reference table rows with documentation hrefs."
              (p (~tw :tokens "text-sm mb-1")
                (str (len (get r "ref-sample")) " attributes with detail page links"))
              (map (fn (item)
                (div (str (get item "name") " → "
                         (or (get item "href") "no detail page"))))
                (get r "ref-sample")))

            (~page-helpers-demo/demo-result-card
              :title "build-attr-detail"
              :ms (get r "attr-ms") :theme "blue"
              :desc "Builds a detail page data structure for a single attribute (sx-get): title, wire ID, handler status."
              (div (str "title: " (get (get r "attr-result") "attr-title")))
              (div (str "wire-id: " (or (get (get r "attr-result") "attr-wire-id") "none")))
              (div (str "has handler: " (if (get (get r "attr-result") "attr-handler") "yes" "no"))))

            (~page-helpers-demo/demo-result-card
              :title "build-component-source"
              :ms (get r "comp-ms") :theme "blue"
              :desc "Reconstructs a defcomp source definition from a component metadata dict (name, params, body)."
              (pre (~tw :tokens "bg-blue-50 p-2 rounded overflow-x-auto")
                (get r "comp-result")))

            (div (~tw :tokens "rounded-lg border border-blue-200 bg-blue-50/30 p-4 md:col-span-2")
              (h4 (~tw :tokens "font-semibold text-blue-700 text-sm mb-1")
                "build-routing-analysis "
                (span (~tw :tokens "text-xs text-blue-400") (str (get r "routing-ms") "ms")))
              (p (~tw :tokens "text-xs text-blue-500 mb-2")
                "Classifies pages as client-routable or server-only based on whether they have data dependencies.")
              (div (~tw :tokens "text-xs text-blue-600")
                (p (~tw :tokens "text-sm mb-1")
                  (str (get (get r "routing-result") "total-pages") " pages: "
                       (get (get r "routing-result") "client-count") " client-routable, "
                       (get (get r "routing-result") "server-count") " server-only"))
                (div (~tw :tokens "space-y-0.5")
                  (map (fn (pg)
                    (div (str (get pg "name") " → " (get pg "mode")
                             (when (not (empty? (get pg "reason")))
                               (str " (" (get pg "reason") ")")))))
                    (get (get r "routing-result") "pages")))))))))))
