;; Events form components — entry edit, slot add/edit, entry add,
;; ticket type add/edit, add buttons, post search results.

;; ---------------------------------------------------------------------------
;; Slot picker option (shared by entry-edit and entry-add)
;; ---------------------------------------------------------------------------

(defcomp ~forms/slot-option (&key value data-start data-end data-flexible data-cost selected label)
  (option :value value :data-start data-start :data-end data-end
          :data-flexible data-flexible :data-cost data-cost
          :selected selected
    label))

(defcomp ~forms/slot-picker (&key id options)
  (select :id id :name "slot_id" :class "w-full border p-2 rounded"
          :data-slot-picker "" :required "required"
    options))

(defcomp ~forms/no-slots ()
  (div :class "text-sm text-stone-500" "No slots defined for this day."))

;; ---------------------------------------------------------------------------
;; Entry edit form (_types/entry/_edit.html)
;; ---------------------------------------------------------------------------

(defcomp ~forms/entry-edit-form (&key entry-id list-container put-url cancel-url csrf
                                       name-val slot-picker
                                       start-val end-val cost-display
                                       ticket-price-val ticket-count-val
                                       action-btn cancel-btn)
  (section :id (str "entry-" entry-id) :class list-container
    (div :id (str "entry-errors-" entry-id) :class "mt-2 text-sm text-red-600")
    (form :class "space-y-3 mt-4" :sx-put put-url
          :sx-target (str "#entry-" entry-id) :sx-swap "outerHTML"
      (input :type "hidden" :name "csrf_token" :value csrf)

      ;; Name
      (div
        (label :class "block text-sm font-medium text-stone-700 mb-1"
               :for (str "entry-name-" entry-id) "Name")
        (input :id (str "entry-name-" entry-id) :name "name"
               :class "w-full border p-2 rounded" :placeholder "Name"
               :value name-val))

      ;; Slot picker
      (div
        (label :class "block text-sm font-medium text-stone-700 mb-1"
               :for (str "entry-slot-" entry-id) "Slot")
        slot-picker)

      ;; Time inputs (flexible slots)
      (div :data-time-fields "" :class "hidden space-y-3"
        (div
          (label :class "block text-sm font-medium text-stone-700 mb-1"
                 :for (str "entry-start-" entry-id) "From")
          (input :id (str "entry-start-" entry-id) :name "start_at" :type "time"
                 :class "w-full border p-2 rounded" :value start-val
                 :data-entry-start ""))
        (div
          (label :class "block text-sm font-medium text-stone-700 mb-1"
                 :for (str "entry-end-" entry-id) "To")
          (input :id (str "entry-end-" entry-id) :name "end_at" :type "time"
                 :class "w-full border p-2 rounded" :value end-val
                 :data-entry-end ""))
        (p :class "text-xs text-stone-500" :data-slot-boundary ""))

      ;; Fixed time summary
      (div :data-fixed-summary "" :class "hidden text-sm text-stone-600")

      ;; Cost display
      (div :data-cost-row "" :class "hidden text-sm font-medium text-stone-700"
        "Estimated Cost: "
        (span :data-cost-display "" :class "text-green-600" cost-display))

      ;; Ticket Configuration
      (div :class "border-t pt-3 mt-3"
        (h4 :class "text-sm font-semibold text-stone-700 mb-3" "Ticket Configuration")
        (div :class "grid grid-cols-2 gap-3"
          (div
            (label :class "block text-sm font-medium text-stone-700 mb-1"
                   :for (str "entry-ticket-price-" entry-id)
              "Ticket Price (£)")
            (input :id (str "entry-ticket-price-" entry-id) :name "ticket_price"
                   :type "number" :step "0.01" :min "0"
                   :class "w-full border p-2 rounded"
                   :placeholder "Leave empty for no tickets"
                   :value ticket-price-val)
            (p :class "text-xs text-stone-500 mt-1" "Leave empty if no tickets needed"))
          (div
            (label :class "block text-sm font-medium text-stone-700 mb-1"
                   :for (str "entry-ticket-count-" entry-id) "Total Tickets")
            (input :id (str "entry-ticket-count-" entry-id) :name "ticket_count"
                   :type "number" :min "0"
                   :class "w-full border p-2 rounded"
                   :placeholder "Leave empty for unlimited"
                   :value ticket-count-val)
            (p :class "text-xs text-stone-500 mt-1" "Leave empty for unlimited"))))

      ;; Buttons
      (div :class "flex justify-end gap-2 pt-2"
        (button :type "button" :class cancel-btn
                :sx-get cancel-url
                :sx-target (str "#entry-" entry-id) :sx-swap "outerHTML"
          "Cancel")
        (button :type "submit" :class action-btn
                :data-confirm "true" :data-confirm-title "Save entry?"
                :data-confirm-text "Are you sure you want to save this entry?"
                :data-confirm-icon "question"
                :data-confirm-confirm-text "Yes, save it"
                :data-confirm-cancel-text "Cancel"
          (i :class "fa fa-save") " Save entry")))))


;; ---------------------------------------------------------------------------
;; Post search results (_types/entry/_post_search_results.html)
;; ---------------------------------------------------------------------------

(defcomp ~forms/post-search-item (&key post-url entry-id csrf post-id
                                         img title)
  (form :sx-post post-url :sx-target (str "#entry-posts-" entry-id) :sx-swap "innerHTML"
        :class "p-2 hover:bg-stone-50 cursor-pointer rounded text-sm border-b"
    (input :type "hidden" :name "csrf_token" :value csrf)
    (input :type "hidden" :name "post_id" :value post-id)
    (button :type "submit" :class "w-full text-left flex items-center gap-2"
            :data-confirm "" :data-confirm-title "Add post?"
            :data-confirm-text (str "Add " title " to this entry?")
            :data-confirm-icon "question"
            :data-confirm-confirm-text "Yes, add it"
            :data-confirm-cancel-text "Cancel"
      img (span title))))

(defcomp ~forms/post-search-sentinel (&key page next-url)
  (div :id (str "post-search-sentinel-" page)
       :sx-get next-url
       :sx-trigger "intersect once delay:250ms, sentinel:retry"
       :sx-swap "outerHTML"
       :_ "
      init
        if not me.dataset.retryMs then set me.dataset.retryMs to 1000 end

      on sentinel:retry
        remove .hidden from .js-loading in me
        add .hidden to .js-neterr in me
        set me.style.pointerEvents to 'none'
        set me.style.opacity to '0'
        trigger htmx:consume on me
        call htmx.trigger(me, 'intersect')
      end

      def backoff()
        add .hidden to .js-loading in me
        remove .hidden from .js-neterr in me
        set myMs to Number(me.dataset.retryMs)
        if myMs < 10000 then set me.dataset.retryMs to myMs * 2 end
        js setTimeout(() => htmx.trigger(me, 'sentinel:retry'), myMs)
      end

      on htmx:beforeRequest
        set me.style.pointerEvents to 'none'
        set me.style.opacity to '0'
      end

      on htmx:afterSwap
        set me.dataset.retryMs to 1000
      end

      on htmx:sendError     call backoff()
      on htmx:responseError call backoff()
      on htmx:timeout       call backoff()
    "
       :role "status" :aria-live "polite" :aria-hidden "true" :class "py-2"
    (div :class "text-xs text-center text-stone-400 js-loading" "Loading more...")
    (div :class "text-xs text-center text-stone-400 js-neterr hidden" "Connection error. Retrying...")))

(defcomp ~forms/post-search-end ()
  (div :class "py-2 text-xs text-center text-stone-400" "End of results"))


;; ---------------------------------------------------------------------------
;; Slot edit form (_types/slot/_edit.html)
;; ---------------------------------------------------------------------------

(defcomp ~forms/day-checkbox (&key name label checked)
  (label :class "flex items-center gap-1 px-2 py-1 rounded-full bg-slate-100"
    (input :type "checkbox" :name name :value "1" :data-day name :checked checked)
    (span label)))

(defcomp ~forms/day-all-checkbox (&key checked)
  (label :class "flex items-center gap-1 px-2 py-1 rounded-full bg-slate-200"
    (input :type "checkbox" :data-day-all "" :checked checked)
    (span "All")))

(defcomp ~forms/slot-edit-form (&key slot-id list-container put-url cancel-url csrf
                                       name-val cost-val start-val end-val desc-val
                                       days flexible-checked
                                       action-btn cancel-btn)
  (section :id (str "slot-" slot-id) :class list-container
    (div :id "slot-errors" :class "mt-2 text-sm text-red-600")
    (form :class "space-y-3 mt-4" :sx-put put-url
          :sx-target (str "#slot-" slot-id) :sx-swap "outerHTML"
          :sx-on:afterRequest "if (event.detail.successful) this.reset()"
      (input :type "hidden" :name "csrf_token" :value csrf)

      ;; Name
      (div
        (label :class "block text-sm font-medium text-stone-700 mb-1"
               :for (str "slot-name-" slot-id) "Name")
        (input :id (str "slot-name-" slot-id) :name "name" :placeholder "Name"
               :class "w-full border p-2 rounded" :value name-val))

      ;; Cost
      (div
        (label :class "block text-sm font-medium text-stone-700 mb-1"
               :for (str "slot-cost-" slot-id) "Cost")
        (input :id (str "slot-cost-" slot-id) :name "cost" :placeholder "Cost e.g. 12.50"
               :class "w-full border p-2 rounded" :value cost-val))

      ;; Start time
      (div
        (label :class "block text-sm font-medium text-stone-700 mb-1"
               :for (str "slot-start-" slot-id) "Start time")
        (input :id (str "slot-start-" slot-id) :name "time_start" :placeholder "Start HH:MM"
               :class "w-full border p-2 rounded" :value start-val))

      ;; End time
      (div
        (label :class "block text-sm font-medium text-stone-700 mb-1"
               :for (str "slot-end-" slot-id) "End time")
        (input :id (str "slot-end-" slot-id) :name "time_end" :placeholder "End HH:MM"
               :class "w-full border p-2 rounded" :value end-val))

      ;; Description
      (div
        (label :class "block text-sm font-medium text-stone-700 mb-1"
               :for (str "slot-desc-" slot-id) "Description")
        (textarea :id (str "slot-desc-" slot-id) :name "description" :rows "2"
                  :placeholder "Description" :class "w-full border p-2 rounded"
          desc-val))

      ;; Days
      (div
        (span :class "block text-sm font-medium text-stone-700 mb-1" "Days")
        (div :class "flex flex-wrap gap-3 items-center text-sm" :data-days-group ""
          days))

      ;; Flexible
      (div
        (label :class "block text-sm font-medium text-stone-700 mb-1"
               :for (str "slot-flexible-" slot-id) "Flexible booking")
        (label :class "inline-flex items-center gap-2 text-xs"
          (input :id (str "slot-flexible-" slot-id) :type "checkbox" :name "flexible"
                 :value "1" :checked flexible-checked)
          (span "Allow bookings at any time within this band")))

      ;; Buttons
      (div :class "flex justify-end gap-2 pt-2"
        (button :type "button" :class cancel-btn
                :sx-get cancel-url
                :sx-target (str "#slot-" slot-id) :sx-swap "outerHTML"
          "Cancel")
        (button :type "submit" :class action-btn
                :data-confirm "true" :data-confirm-title "Save slot?"
                :data-confirm-text "Are you sure you want to save this slot?"
                :data-confirm-icon "question"
                :data-confirm-confirm-text "Yes, save it"
                :data-confirm-cancel-text "Cancel"
          (i :class "fa fa-save") " Save slot")))))


;; ---------------------------------------------------------------------------
;; Slot add form (_types/slots/_add.html)
;; ---------------------------------------------------------------------------

(defcomp ~forms/slot-add-form (&key post-url csrf days action-btn cancel-btn cancel-url)
  (form :sx-post post-url :sx-target "#slots-table" :sx-select "#slots-table"
        :sx-disinherit "sx-select" :sx-swap "outerHTML"
        :sx-headers csrf :class "space-y-3"
    (div :class "grid grid-cols-1 md:grid-cols-4 gap-3"
      (div :class "md:col-span-2"
        (label :class "block text-xs font-semibold mb-1" "Name")
        (input :type "text" :name "name" :class "w-full border rounded px-2 py-1 text-sm" :required "required"))
      (div :class "md:col-span-2"
        (label :class "block text-xs font-semibold mb-1" "Description")
        (input :type "text" :name "description" :class "w-full border rounded px-2 py-1 text-sm"))
      (div
        (label :class "block text-xs font-semibold mb-1" "Days")
        (div :class "flex flex-wrap gap-1 text-xs" :data-days-group ""
          days))
      (div
        (label :class "block text-xs font-semibold mb-1" "Time start")
        (input :type "time" :name "time_start" :class "w-full border rounded px-2 py-1 text-sm" :required "required"))
      (div
        (label :class "block text-xs font-semibold mb-1" "Time end")
        (input :type "time" :name "time_end" :class "w-full border rounded px-2 py-1 text-sm" :required "required"))
      (div
        (label :class "block text-xs font-semibold mb-1" "Cost")
        (input :type "text" :name "cost" :class "w-full border rounded px-2 py-1 text-sm" :placeholder "e.g. 5.00"))
      (div :class "md:col-span-2"
        (label :class "block text-xs font-semibold mb-1" "Flexible booking")
        (label :class "inline-flex items-center gap-2 text-xs"
          (input :type "checkbox" :name "flexible" :value "1")
          (span "Allow bookings at any time within this band"))))
    (div :class "flex justify-end gap-2 pt-2"
      (button :type "button" :class cancel-btn
              :sx-get cancel-url :sx-target "#slot-add-container" :sx-swap "innerHTML"
        "Cancel")
      (button :type "submit" :class action-btn
              :data-confirm "true" :data-confirm-title "Add slot?"
              :data-confirm-text "Are you sure you want to add this slot?"
              :data-confirm-icon "question"
              :data-confirm-confirm-text "Yes, add it"
              :data-confirm-cancel-text "Cancel"
        (i :class "fa fa-save") " Save slot"))))

(defcomp ~forms/slot-add-button (&key pre-action add-url)
  (button :type "button" :class pre-action
          :sx-get add-url :sx-target "#slot-add-container" :sx-swap "innerHTML"
    "+ Add slot"))


;; ---------------------------------------------------------------------------
;; Composition defcomps — receive data, compose form trees
;; ---------------------------------------------------------------------------

;; Day checkboxes from data — replaces Python loop
(defcomp
  ~forms/day-checkboxes-from-data
  (&key days-data all-checked)
  (<>
    (~forms/day-all-checkbox :checked (when all-checked "checked"))
    (map
      (lambda
        (d)
        (let-match
          {:checked checked :label label :name name}
          d
          (~forms/day-checkbox
            :name name
            :label label
            :checked (when checked "checked"))))
      (or days-data (list)))))

;; Slot options from data — replaces _slot_options_html Python loop
(defcomp
  ~forms/slot-options-from-data
  (&key slots)
  (<>
    (map
      (lambda
        (s)
        (let-match
          {:data-end data-end :data-flexible data-flexible :selected selected :value value :data-cost data-cost :label label :data-start data-start}
          s
          (~forms/slot-option
            :value value
            :data-start data-start
            :data-end data-end
            :data-flexible data-flexible
            :data-cost data-cost
            :selected selected
            :label label)))
      (or slots (list)))))

;; Slot picker from data — wraps picker + options
(defcomp ~forms/slot-picker-from-data (&key id slots)
  (if (empty? (or slots (list)))
    (~forms/no-slots)
    (~forms/slot-picker
      :id id
      :options (~forms/slot-options-from-data :slots slots))))

;; Slot edit form from data
(defcomp ~forms/slot-edit-form-from-data (&key slot-id list-container put-url cancel-url csrf
                                                  name-val cost-val start-val end-val desc-val
                                                  days-data all-checked flexible-checked
                                                  action-btn cancel-btn)
  (~forms/slot-edit-form
    :slot-id slot-id :list-container list-container
    :put-url put-url :cancel-url cancel-url :csrf csrf
    :name-val name-val :cost-val cost-val :start-val start-val
    :end-val end-val :desc-val desc-val
    :days (~forms/day-checkboxes-from-data :days-data days-data :all-checked all-checked)
    :flexible-checked flexible-checked
    :action-btn action-btn :cancel-btn cancel-btn))

;; Slot add form from data
(defcomp ~forms/slot-add-form-from-data (&key post-url csrf days-data action-btn cancel-btn cancel-url)
  (~forms/slot-add-form
    :post-url post-url :csrf csrf
    :days (~forms/day-checkboxes-from-data :days-data days-data)
    :action-btn action-btn :cancel-btn cancel-btn :cancel-url cancel-url))


;; ---------------------------------------------------------------------------
;; Entry add form (_types/day/_add.html)
;; ---------------------------------------------------------------------------

(defcomp ~forms/entry-add-form (&key post-url csrf slot-picker
                                       action-btn cancel-btn cancel-url)
  (<>
    (div :id "entry-errors" :class "mt-2 text-sm text-red-600")
    (form :class "mt-4 grid grid-cols-1 md:grid-cols-4 gap-2"
          :sx-post post-url :sx-target "#day-entries"
          :sx-on:afterRequest "if (event.detail.successful) this.reset()"
          :sx-swap "innerHTML"
      (input :type "hidden" :name "csrf_token" :value csrf)

      ;; Entry name
      (input :name "name" :type "text" :required "required"
             :class "border rounded px-3 py-2" :placeholder "Entry name")

      ;; Slot picker
      slot-picker

      ;; Time entry + cost display
      (div :class "md:col-span-2 flex flex-col gap-2"
        ;; Time inputs (flexible)
        (div :data-time-fields "" :class "hidden"
          (div :class "mb-2"
            (label :class "block text-xs font-medium text-stone-700 mb-1" "From")
            (input :name "start_time" :type "time" :class "border rounded px-3 py-2 w-full"
                   :data-entry-start ""))
          (div :class "mb-2"
            (label :class "block text-xs font-medium text-stone-700 mb-1" "To")
            (input :name "end_time" :type "time" :class "border rounded px-3 py-2 w-full"
                   :data-entry-end ""))
          (p :class "text-xs text-stone-500" :data-slot-boundary ""))
        ;; Cost display
        (div :data-cost-row "" :class "hidden text-sm font-medium text-stone-700"
          "Estimated Cost: "
          (span :data-cost-display "" :class "text-green-600" "£0.00"))
        ;; Fixed summary
        (div :data-fixed-summary "" :class "hidden text-sm text-stone-600"))

      ;; Ticket Configuration
      (div :class "md:col-span-4 border-t pt-3 mt-2"
        (h4 :class "text-sm font-semibold text-stone-700 mb-3" "Ticket Configuration (Optional)")
        (div :class "grid grid-cols-2 gap-3"
          (div
            (label :class "block text-xs font-medium text-stone-700 mb-1"
              "Ticket Price (£)")
            (input :name "ticket_price" :type "number" :step "0.01" :min "0"
                   :class "w-full border rounded px-3 py-2 text-sm"
                   :placeholder "Leave empty for no tickets"))
          (div
            (label :class "block text-xs font-medium text-stone-700 mb-1" "Total Tickets")
            (input :name "ticket_count" :type "number" :min "0"
                   :class "w-full border rounded px-3 py-2 text-sm"
                   :placeholder "Leave empty for unlimited"))))

      ;; Buttons
      (div :class "flex justify-end gap-2 pt-2 md:col-span-4"
        (button :type "button" :class cancel-btn
                :sx-get cancel-url :sx-target "#entry-add-container" :sx-swap "innerHTML"
          "Cancel")
        (button :type "submit" :class action-btn
                :data-confirm "true" :data-confirm-title "Add entry?"
                :data-confirm-text "Are you sure you want to add this entry?"
                :data-confirm-icon "question"
                :data-confirm-confirm-text "Yes, add it"
                :data-confirm-cancel-text "Cancel"
          (i :class "fa fa-save") " Save entry")))))

(defcomp ~forms/entry-add-button (&key pre-action add-url)
  (button :type "button" :class pre-action
          :sx-get add-url :sx-target "#entry-add-container" :sx-swap "innerHTML"
    "+ Add entry"))


;; ---------------------------------------------------------------------------
;; Ticket type edit form (_types/ticket_type/_edit.html)
;; ---------------------------------------------------------------------------

(defcomp ~forms/ticket-type-edit-form (&key ticket-id list-container put-url cancel-url csrf
                                              name-val cost-val count-val
                                              action-btn cancel-btn)
  (section :id (str "ticket-" ticket-id) :class list-container
    (div :id "ticket-errors" :class "mt-2 text-sm text-red-600")
    (form :class "space-y-3 mt-4" :sx-put put-url
          :sx-target (str "#ticket-" ticket-id) :sx-swap "outerHTML"
          :sx-on:afterRequest "if (event.detail.successful) this.reset()"
      (input :type "hidden" :name "csrf_token" :value csrf)

      ;; Name
      (div
        (label :class "block text-sm font-medium text-stone-700 mb-1"
               :for (str "ticket-name-" ticket-id) "Name")
        (input :id (str "ticket-name-" ticket-id) :name "name"
               :placeholder "e.g. Adult, Child, Student"
               :class "w-full border p-2 rounded" :value name-val :required "required"))

      ;; Cost
      (div
        (label :class "block text-sm font-medium text-stone-700 mb-1"
               :for (str "ticket-cost-" ticket-id) "Cost (£)")
        (input :id (str "ticket-cost-" ticket-id) :name "cost" :type "number"
               :step "0.01" :min "0" :placeholder "e.g. 5.00"
               :class "w-full border p-2 rounded" :value cost-val :required "required"))

      ;; Count
      (div
        (label :class "block text-sm font-medium text-stone-700 mb-1"
               :for (str "ticket-count-" ticket-id) "Count")
        (input :id (str "ticket-count-" ticket-id) :name "count" :type "number"
               :min "0" :placeholder "e.g. 50"
               :class "w-full border p-2 rounded" :value count-val :required "required"))

      ;; Buttons
      (div :class "flex justify-end gap-2 pt-2"
        (button :type "button" :class cancel-btn
                :sx-get cancel-url
                :sx-target (str "#ticket-" ticket-id) :sx-swap "outerHTML"
          "Cancel")
        (button :type "submit" :class action-btn
                :data-confirm "true" :data-confirm-title "Save ticket type?"
                :data-confirm-text "Are you sure you want to save this ticket type?"
                :data-confirm-icon "question"
                :data-confirm-confirm-text "Yes, save it"
                :data-confirm-cancel-text "Cancel"
          (i :class "fa fa-save") " Save ticket type")))))


;; ---------------------------------------------------------------------------
;; Ticket type add form (_types/ticket_types/_add.html)
;; ---------------------------------------------------------------------------

(defcomp ~forms/ticket-type-add-form (&key post-url csrf action-btn cancel-btn cancel-url)
  (form :sx-post post-url :sx-target "#tickets-table" :sx-select "#tickets-table"
        :sx-disinherit "sx-select" :sx-swap "outerHTML"
        :sx-headers csrf :class "space-y-3"
    (div :class "grid grid-cols-1 md:grid-cols-3 gap-3"
      (div
        (label :class "block text-xs font-semibold mb-1" "Name")
        (input :type "text" :name "name" :class "w-full border rounded px-2 py-1 text-sm"
               :placeholder "e.g. Adult, Child, Student" :required "required"))
      (div
        (label :class "block text-xs font-semibold mb-1" "Cost (£)")
        (input :type "number" :name "cost" :step "0.01" :min "0"
               :class "w-full border rounded px-2 py-1 text-sm"
               :placeholder "e.g. 5.00" :required "required"))
      (div
        (label :class "block text-xs font-semibold mb-1" "Count")
        (input :type "number" :name "count" :min "0"
               :class "w-full border rounded px-2 py-1 text-sm"
               :placeholder "e.g. 50" :required "required")))
    (div :class "flex justify-end gap-2 pt-2"
      (button :type "button" :class cancel-btn
              :sx-get cancel-url :sx-target "#ticket-add-container" :sx-swap "innerHTML"
        "Cancel")
      (button :type "submit" :class action-btn
              :data-confirm "true" :data-confirm-title "Add ticket type?"
              :data-confirm-text "Are you sure you want to add this ticket type?"
              :data-confirm-icon "question"
              :data-confirm-confirm-text "Yes, add it"
              :data-confirm-cancel-text "Cancel"
        (i :class "fa fa-save") " Save ticket type"))))

(defcomp ~forms/ticket-type-add-button (&key action-btn add-url)
  (button :class action-btn
          :sx-get add-url :sx-target "#ticket-add-container" :sx-swap "innerHTML"
    (i :class "fa fa-plus") " Add ticket type"))


;; ---------------------------------------------------------------------------
;; Entry admin nav — placeholder
;; ---------------------------------------------------------------------------

(defcomp ~forms/admin-placeholder-nav ()
  (div :class "relative nav-group"
    (span :class "block px-3 py-2 text-stone-400 text-sm italic" "Admin options")))