;; 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

(ns app.main.broadcast
  "BroadcastChannel API."
  (:require
   [app.common.exceptions :as ex]
   [app.common.transit :as t]
   [beicon.v2.core :as rx]
   [potok.v2.core :as ptk]))

(defrecord BroadcastMessage [id type data]
  cljs.core/IDeref
  (-deref [_] data))

(def ^:const default-topic "penpot")

;; The main broadcast channel instance, used for emit data
;; If used as a library may be we can't access js/BroadcastChannel.
;; and even if it exists we can receive an exception like:
;; Failed to construct 'BroadcastChannel': Can't create BroadcastChannel in an opaque origin
(defonce default-channel
  (when (exists? js/BroadcastChannel)
    (ex/ignoring (js/BroadcastChannel. default-topic))))

(defonce stream
  (if (exists? js/BroadcastChannel)
    (->> (rx/create (fn [subs]
                      (let [chan (js/BroadcastChannel. default-topic)]
                        (unchecked-set chan "onmessage" #(rx/push! subs (unchecked-get % "data")))
                        (fn [] (.close ^js chan)))))
         (rx/map t/decode-str)
         (rx/map map->BroadcastMessage)
         (rx/share))
    (rx/subject)))

(defn emit!
  ([type data]
   (when default-channel
     (.postMessage ^js default-channel (t/encode-str {:id nil :type type :data data}))
     nil))
  ([id type data]
   (when default-channel
     (.postMessage ^js default-channel (t/encode-str {:id id :type type :data data}))
     nil)))

(defn type?
  ([type]
   (fn [obj] (= (:type obj) type)))
  ([obj type]
   (= (:type obj) type)))

(defn event
  [type data]
  (ptk/reify ::event
    ptk/EffectEvent
    (effect [_ _ _]
      (emit! type data))))
