;; Two on-screen widgets for the thin client: now-playing and the idle-gallery
;; weather/clock overlay. Installed to
;; /home/<KIOSK_USERNAME>/.config/eww/eww.yuck by build-thin-client-iso.sh.
;;
;; Data sources are separate `deflisten`/`defpoll` processes, NOT thinclient_agent —
;; now-playing uses /usr/local/bin/now-playing-json (`playerctl --follow`), the
;; weather overlay uses /usr/local/bin/weather-json (MQTT). The agent is a *system*
;; service that deliberately outlives the compositor, whereas both widgets are
;; session-scoped and die with sway; wiring either to the agent would mean either
;; restarting the agent whenever a widget restarts, or opening a second inbound
;; control channel into it, which the security boundary in mqtt_discovery.py rules
;; out. The cost is one extra subscription each, which is negligible.
;;
;; The :onclick strings below are fixed constants in this file. Nothing from MQTT, HA,
;; or player metadata is ever interpolated into them.

(defvar players "mpv,spotifyd,%any")

(deflisten nowplaying
  :initial '{"visible":false,"title":"","artist":"","art":"","controls":false}'
  "/usr/local/bin/now-playing-json")

(defwidget np-meta []
  (box :orientation "vertical" :space-evenly false :halign "start" :valign "center" :hexpand true
    (label :class "np-title"  :text nowplaying.title  :halign "start" :limit-width 34 :truncate true)
    (label :class "np-artist" :text nowplaying.artist :halign "start" :limit-width 34 :truncate true)))

;; Hidden rather than absent when the player exposes no transport control (some
;; sources only report metadata) — the widget then degrades to art + text.
(defwidget np-controls []
  (box :class "np-controls" :orientation "horizontal" :space-evenly true :spacing 4
       :visible {nowplaying.controls} :valign "center"
    (button :class "np-btn" :onclick "playerctl -p ${players} previous"   "⏮")
    (button :class "np-btn" :onclick "playerctl -p ${players} play-pause" "⏯")
    (button :class "np-btn" :onclick "playerctl -p ${players} next"       "⏭")))

(defwidget np-root []
  (box :class "np-root" :orientation "horizontal" :space-evenly false :spacing 12
       :visible {nowplaying.visible}
    (image :class "np-art" :path nowplaying.art :image-width 72 :image-height 72)
    (np-meta)
    (np-controls)))

;; :exclusive false — the widget floats over whatever is on screen and must never
;; reserve layer-shell space, or it would shrink the fullscreen media surfaces this
;; whole image exists to show. Visibility is owned by fullscreen-watcher.sh, which
;; opens and closes this window; the :visible binding above only handles "nothing is
;; playing at all".
(defwindow now-playing
  :monitor 0
  :geometry (geometry :x "24px" :y "24px" :anchor "bottom left"
                      :width "420px" :height "96px")
  :stacking "overlay"
  :exclusive false
  :focusable false
  (np-root))

;; --- Idle-gallery weather/clock overlay --------------------------------------
;;
;; Time/date/weekday are computed locally (no Home Assistant round-trip needed for
;; those — the box already has a clock) via `date`(1); only temperature/condition/
;; location come from weather-json's MQTT subscription, see that script's own
;; docstring for the smarthome/weather/current data contract. A missing/never-
;; published weather reading degrades to just hiding the weather line — the clock
;; and date keep showing regardless, same "never blank the whole thing over one
;; missing part" rule this repo applies everywhere (digest render.js, admin-canvas
;; render.js, idle-gallery.sh's own fallback chain).
(defpoll clock_time    :interval "20s" :initial "--:--" "date +'%H:%M'")
(defpoll clock_weekday :interval "60s" :initial ""       "date +'%A'")
(defpoll clock_date    :interval "60s" :initial ""       "date +'%-d %B'")

(deflisten weatherinfo
  :initial '{"available":false,"temperature":"","condition":"","location":""}'
  "/usr/local/bin/weather-json")

(defwidget weather-overlay-root []
  (box :class "wo-root" :orientation "vertical" :space-evenly false :halign "end"
    (label :class "wo-time" :text clock_time)
    (label :class "wo-date" :text "${clock_weekday}, ${clock_date}")
    (box :class "wo-weather" :orientation "horizontal" :space-evenly false :halign "end"
         :visible {weatherinfo.available}
      (label :class "wo-location" :text weatherinfo.location)
      (label :class "wo-sep" :text " · " :visible {weatherinfo.location != ""})
      (label :class "wo-temp" :text weatherinfo.temperature)
      (label :class "wo-sep" :text " · ")
      (label :class "wo-condition" :text weatherinfo.condition))))

;; Same :exclusive false/:stacking "overlay" shape as now-playing, and the same
;; ownership split: visibility is entirely owned by idle-gallery.sh, which is the
;; one thing that actually knows when its own slideshow is the thing on screen —
;; opened right before the slideshow's mpv is launched, closed in stop_slideshow().
;; No :visible gate at the window level the way now-playing has one, because there
;; is no "open but should still hide" sub-case here: once idle-gallery owns the
;; screen, showing at least the clock is always correct.
(defwindow weather-overlay
  :monitor 0
  :geometry (geometry :x "32px" :y "32px" :anchor "top right"
                      :width "440px" :height "140px")
  :stacking "overlay"
  :exclusive false
  :focusable false
  (weather-overlay-root))
