;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) KALEIDOS INC Sucursal en España SL

(ns app.util.theme
  (:require
   [app.common.data :as d]
   [app.util.globals :as globals]
   [beicon.v2.core :as rx]
   [rumext.v2 :as mf]))

(defonce ^:private color-scheme-media-query
  (.matchMedia globals/window "(prefers-color-scheme: dark)"))

(defonce ^:private color-scheme-listeners*
  (atom #{}))

(def ^:const default "dark")

(defn get-system-theme
  []
  (if ^boolean (.-matches color-scheme-media-query)
    "dark"
    "light"))

(defn- notify-color-scheme-listeners!
  []
  (doseq [f @color-scheme-listeners*]
    (f)))

(defn add-color-scheme-listener!
  "Registers `f` to run after each `body` color-scheme update in
   `use-initialize` (profile theme or OS preference). Returns a dispose fn."
  [f]
  (swap! color-scheme-listeners* conj f)
  (fn [] (swap! color-scheme-listeners* disj f)))

(defn- set-color-scheme
  [^string color]

  (let [node  (.querySelector js/document "body")
        class (if (= color "dark") "default" "light")]
    (.removeAttribute node "class")
    (.add ^js (.-classList ^js node) class)))

(defn resolve-theme
  "Resolves the profile's theme setting to the effective UI theme ('dark' or
  'light'): 'system' follows the given system theme, 'default' and an unset
  theme mean dark, and any other value is taken as-is. Single source of truth
  for the app's own theme and the theme reported to plugins."
  [profile-theme system-theme]
  (cond
    (= profile-theme "system") system-theme
    (= profile-theme "default") "dark"
    :else (d/nilv profile-theme "dark")))

(defn use-initialize
  [{profile-theme :theme}]
  (let [system-theme* (mf/use-state get-system-theme)
        system-theme  (deref system-theme*)]

    (mf/with-effect []
      (let [s (->> (rx/from-event color-scheme-media-query "change")
                   (rx/map #(if (.-matches %) "dark" "light"))
                   (rx/subs! #(reset! system-theme* %)))]
        (fn []
          (rx/dispose! s))))

    (mf/with-effect [system-theme profile-theme]
      (set-color-scheme (resolve-theme profile-theme system-theme))
      (notify-color-scheme-listeners!))))
