(ns auto-ap.ssr.hx
  (:require [auto-ap.ssr.hiccup-helper :as hh]
            [cheshire.core :as cheshire]
            [cheshire.generate :refer [add-encoder]]
            [clojure.string :as str]))


(defn vals [m]
  (cheshire/generate-string m))

(deftype jsfn [body name])

(defn jsf [t jq]
  (.writeString jq (str "__" (.-name t) "__" (.-body t) "__end__")))

(add-encoder jsfn jsf)


(defn json [m]
  (let [starting-point (cheshire/generate-string m)]
    (if (map? m)
      (reduce 
        (fn [starting-point [k v]]
          (if (instance? jsfn v)
            (-> (str/replace starting-point (re-pattern (str "(?s)\"__" (.-name v) "__(.*?)__end__\"")) "$1" )
                (str/replace "\\n" "\n"))
            starting-point))
        starting-point
        m)
      starting-point)))

(defn random-alpha-string []
  (let [alpha-chars (concat (map char (range 65 91))  ; A-Z
                            (map char (range 97 123))) ; a-z
        random-char (fn [] (rand-nth alpha-chars))]
    (apply str (repeatedly 10 random-char))))

(defn js-fn [s]
  (jsfn. s (random-alpha-string)))

(defn trigger-field-change [& {:keys [name
                                      from]}]
  (format "change[target.name==\"%s\"] %s"
          name
          (when from (str "from:" from))))

(defn triggers [& triggers]
  (str/join ", " triggers))

(defn alpine-appear [m]
  (assoc m
         "x-transition:enter" "transition-opacity duration-500"
         "x-transition:enter-start" "opacity-0"
         "x-transition:enter-end" "opacity-100"))

(defn alpine-disappear [m]
  (assoc m
         "x-transition:leave" "transition duration-500"
         "x-transition:leave-start" "opacity-100"
         "x-transition:leave-end" "opacity-0"))

(defn alpine-mount-then-appear [{:keys [data-key] :as params}]
  (merge (-> {:x-data (json {data-key false})
              :x-init (format "$nextTick(() => %s=true)" (name data-key))
              :x-show (name data-key)}
             alpine-appear
             alpine-disappear)
         (dissoc params :data-key)))

(defn alpine-mount-then-disappear [{:keys [data-key] :as params :or {data-key "show"}} ]
  (merge (-> {:x-data (json {data-key true})
              :x-init (format "$nextTick(() => %s=false)" (name data-key))
              :x-show (name data-key)}
             alpine-appear
             alpine-disappear)
         (dissoc params :data-key)))

(defn bind-alpine-vals [m field->alpine-field]
  (assoc m "x-bind:hx-vals"

         (format "JSON.stringify({%s})"
                 (str/join ", "
                           (map
                            (fn [[field alpine-field]]
                              (format "\"%s\": $data.%s || ''" field alpine-field))

                            field->alpine-field)))))
                             
(defn trigger-click-or-enter [m]
  (assoc m :hx-trigger "click, keyup[keyCode==13]"))

(defn htmx-transition-appear [params]
  (-> params 
      (update :class (fn [c]
                       (-> (or c "")
                           (hh/add-class "opacity-100 transition htmx-added:opacity-0 duration-300")))))
  )
