#_{:clj-kondo/ignore [:unused-namespace]}
(ns auto-ap.subs
  (:require [re-frame.core :as re-frame]
            [auto-ap.utils :refer [by]]
            [auto-ap.views.utils :refer [parse-jwt]]
            [clojure.string :as str]
            [goog.crypt.base64 :as base64]
            [minisearch :as ms]
            [clojure.set :as set]))
(set! *warn-on-infer* true)

#_{:clj-kondo/ignore [:clojure-lsp/unused-public-var :unresolved-symbol]}
(def MiniSearch (if ms (aget ms "default")
                    nil))

(re-frame/reg-sub
 ::client
 :<- [::selected-clients]
 (fn [selected-clients]
   (when (= 1 (count selected-clients))
     (first selected-clients))))

(re-frame/reg-sub
 ::clients
 (fn [db]
   (when (:user db)
     (sort-by :name (vals (:clients db))))))

(re-frame/reg-sub
  ::selected-clients-raw
  (fn [db]
    (:selected-clients db)))


(defn coerce-string-version [x]
  (if (string? x)
    (js/parseInt x)
    x))

(re-frame/reg-sub
  ::selected-clients
  :<- [::selected-clients-raw]
  :<- [::user]
  :<- [::clients]
  (fn [[selected-clients user clients]]
    (cond (= :mine selected-clients)
          (sort-by :name
                   (:user/clients user))

          (or (and (sequential? selected-clients)
                   (empty? selected-clients))
              (= :all selected-clients)
              (nil? selected-clients))
          clients

          (:group selected-clients)
          (let [group (:group selected-clients)]
            (filterv
             (fn [c]
               ((set (:groups c)) group))
             clients))

          (:selected selected-clients)
          (filter (comp (set (:selected selected-clients)) coerce-string-version :id)
                  clients)

          :else
          nil)))

(re-frame/reg-sub
  ::client-refs
  :<- [::clients]
  (fn [c]
    (map #(select-keys % [:id :name]) c)))


(re-frame/reg-sub
 ::bank-accounts
 :<- [::clients]
 :<- [::client]
 (fn [[clients client]]
   (if client
     (:bank-accounts client)
     (reduce (fn [result {:keys [bank-accounts]}]
               (into result bank-accounts))
             []
             clients))))

(re-frame/reg-sub
 ::bank-accounts-by-id
 :<- [::bank-accounts]
 (fn [as]
   (by :id as)))

;; Bank accounts only, not including cash
(re-frame/reg-sub
 ::real-bank-accounts 
 :<- [::client]
 (fn [client]
   (->> client :bank-accounts (filter #(= (:type %) :check)) (sort-by :sort-order))))

(re-frame/reg-sub
 ::real-bank-accounts-for-client
 (fn [db [_ {:keys [id]}]]
   (sort-by :sort-order (-> db :clients (get id) :bank-accounts ))))

(re-frame/reg-sub
 ::locations-for-client
 
 (fn [db [_ client]]
   (:locations (get (:clients db) (or client (:client db))))))

(re-frame/reg-sub
 ::forecasted-transactions-for-client
 (fn [db [_ client]]
   (:forecasted-transactions (get (:clients db) (or client (:client db))))))

(re-frame/reg-sub
 ::locations-for-client-or-bank-account
 (fn [db [_ client-id bank-account-id]]
   (let [client (get (:clients db) (or client-id (:client db)))
         client-locations (:locations client)
         bank-account-locations (-> (by :id (:bank-accounts client))
                                    (get bank-account-id)
                                    :locations)]
     (or (seq bank-account-locations) client-locations))))

(re-frame/reg-sub
 ::clients-by-id
 (fn [db]
   (when (:user db)
     (:clients db))))

(re-frame/reg-sub
 ::menu-active?
 (fn [db [_ id]]
   (-> db :menu (get id) :active?)))


(re-frame/reg-sub
 ::is-initial-loading?
 (fn [db]
   (:is-initial-loading? db)))

(re-frame/reg-sub
 ::intuit-bank-accounts
 (fn [db]
   (::intuit-bank-accounts db)))

(re-frame/reg-sub
 ::token
 (fn [db]
   (:user db)))

(re-frame/reg-sub
 ::admin
 (fn [db]
   (:admin db)))

(re-frame/reg-sub
 ::is-admin?
 :<- [::user]
 (fn [user]
   (= "admin" (:user/role user))))

(re-frame/reg-sub
 ::is-power-user?
 :<- [::user]
 (fn [user]
   (or (= "power-user" (:user/role user))
       (= "power_user" (:user/role user)))))

(re-frame/reg-sub
 ::user
 (fn [db]
   (parse-jwt (:user db))))

(re-frame/reg-sub
  ::active-route
  (fn [db]
    (:active-route db)))

(re-frame/reg-sub
 ::active-page
 :<- [::active-route]
 (fn [route]
   (or ({:admin-specific-client :admin-clients
         :admin-specific-bank-account :admin-clients}
        route)
       route)))

(re-frame/reg-sub
 ::query-params
 (fn [db]
   (:query-params db)))

(re-frame/reg-sub
  ::route-params
  (fn [db]
    (:route-params db)))

(re-frame/reg-sub
 ::page-failure
 (fn [db]
   (when-let [error (-> db :page-failure first)] 
     (if (= 500 (:status error))
       "System error occured. If you are stuck, please notify ben@integreatconsult.com."
       (:message error)))))
