(ns auto-ap.status
  (:require [re-frame.core :as re-frame]))

;; (re-frame/reg-sub
;;  ::status
;;  (fn [db [_ which]]
;;    (get-in db [::status which])))
;; 
;; 
;; (defn loading [db which]
;;   (-> db 
;;       (assoc-in [::status which :state] :loading)
;;       (assoc-in [::status which :error] nil)))
;; 
;; (defn completion [db which]
;;   (-> db 
;;       (assoc-in [::status which :state] :loading)
;;       (assoc-in [::status which :error] nil)))
;; 
;; (defn triggers-loading [which]
;;   (re-frame/enrich
;;    (fn [db event]
;;      (loading db which))))
;; 
;; (defn triggers-completion [which]
;;   (re-frame/enrich
;;    (fn [db event]
;;      (completion db which))))
;; 
(defn class-for [which]
  (cond (= :loading (:state which))
    ["is-loading"]

    (= :error (:state which))
    ["animated" "shake"]

    :else
    []))

(defn disabled-for [which]
  (cond (= :loading (:state which))
        true

        (= :error (:state which))
        false

        :else
        false))

(defn disabled-if-any [states]
  (if (some #(= :loading (:state %))
            (vals states))
    true
    false))


(re-frame/reg-sub
 ::multi
 (fn [db [_ multi]]
   (get-in db [::status multi])))

(re-frame/reg-sub
 ::last-multi
 (fn [db [_ multi]]
   (last (vals (get-in db [::status multi])))))

(re-frame/reg-sub
 ::single
 (fn [db [_ single]]
   (get-in db [::status single])))

(re-frame/reg-event-db
 ::loading-multi
 [(re-frame/path [::status]) ]
 (fn [db [_ multi which]]
   (assoc-in db [multi which] {:state :loading
                               :error nil})))

(re-frame/reg-event-db
 ::completed-multi
 [(re-frame/path [::status]) ]
 (fn [db [_ multi which]]
   (assoc-in db [multi which] {:state nil
                               :error nil})))

(re-frame/reg-event-db
 ::error-multi
 [(re-frame/path [::status]) ]
 (fn [db [_ multi which error]]
   (assoc-in db [multi which] {:state :error
                               :error error})))

(defn reset-multi [db multi]
  (assoc-in db [::status multi] {}))

(re-frame/reg-event-db
 ::loading
 [(re-frame/path [::status]) ]
 (fn [db [_ single]]
   (assoc db single {:state :loading
                     :error nil})))

(re-frame/reg-event-db
 ::dispose-single
 [(re-frame/path [::status]) ]
 (fn [db [_ single]]
   (dissoc db single )))

(re-frame/reg-event-db
 ::completed
 [(re-frame/path [::status]) ]
 (fn [db [_ single _]]
   (assoc db single {:state nil
                     :error nil})))

(re-frame/reg-event-db
 ::error
 [(re-frame/path [::status]) ]
 (fn [db [_ single error]]
   (assoc db single {:state :error
                     :info nil
                     :error error})))

(re-frame/reg-event-db
 ::info
 [(re-frame/path [::status]) ]
 (fn [db [_ single info]]
   (assoc db single {:info info})))

(defn status-notification [{:keys [statuses]}]
  (let [states (mapv #(deref (re-frame/subscribe %)) statuses)
        error-states
        (->> states
             (filter #(= :error (:state %))))
        info-states
        (->> states (filter #(:info %)))]
    [:<> 
     (when (seq error-states)
       [:div.notification.is-danger.is-light
        (for [state states
              state (:error state)]
          ^{:key (:message state)}
          [:p (or (:message state)
                  (:error state)
                  "An unexpected error occured.")])])
     (when (seq info-states)
       [:div.notification.is-info.is-light
        (for [state states]
          ^{:key (:info state)}
          [:p (:info state)])])]))

(defn big-loader [status]
  (when (= :loading (:state status))
    [:div.container 
     [:div.column.is-4.is-offset-4.has-text-centered
      [:div.loader.is-loading.is-active.big.is-centered]]]))
