(ns auto-ap.permissions
  #?(:clj 
     (:require [cemerick.url :as url])))

;; TODO after getting rid of cljs, use malli schemas to decode this
(defn get-client-id [client]
  (cond (nat-int? client)
        client

        (:db/id client)
        (:db/id client)

        :else
        nil))

(defn can? [user {:keys [client subject activity]}]
  (let [role (or (:user/role user) (:role user) user)
        client-id (get-client-id client)]
    (cond (#{:user-role/admin "admin"} role)
          true

          (and client-id (not (get (into #{} (map :db/id (or (:clients user)
                                                             (:user/clients user)))) client-id)))
          false

          (#{:user-role/power-user "power-user"} role)
          (cond
            (#{:invoice-page :payment-page :my-company-page :transaction-page :ledger-page} subject)
            true

            (= [:invoice :import] [subject activity])
            true

            (= [:invoice :create] [subject activity])
            true

            (= [:invoice :pay] [subject activity])
            true

            (= [:invoice :edit] [subject activity])
            true

            (= [:invoice :delete] [subject activity])
            true

            (= [:sales :read] [subject activity])
            true

            (= [:vendor :create] [subject activity])
            true

            (= [:vendor :edit] [subject activity])
            true

            (= [:ledger :read] [subject activity])
            true

            (= [:balance-sheet :read] [subject activity])
            true

            :else false)

          (#{:user-role/manager "manager"} role)
          (cond
            (#{:invoice-page :payment-page :my-company-page :transaction-page} subject)
            true

            (= [:vendor :create] [subject activity])
            true

            (= [:vendor :edit] [subject activity])
            true

            (= [:invoice :create] [subject activity])
            true

            (= [:invoice :pay] [subject activity])
            true

            (= [:invoice :edit] [subject activity])
            true

            (= [:invoice :delete] [subject activity])
            true

            (= [:ledger :read] [subject activity])
            true

            (= [:balance-sheet :read] [subject activity])
            true

            :else false)

          (#{:user-role/read-only "read-only"} role)
          (cond
            (= :ledger-page subject) true

            (= [:ledger :read] [subject activity])
            true

            (= [:balance-sheet :read] [subject activity])
            true

            :else false)

          (#{:user-role/user "user"} role)
          (cond
            (#{:invoice-page :payment-page :my-company-page :transaction-page :ledger-page} subject)
            true
          
            (= [:vendor :create] [subject activity])
            true
          
            (= [:vendor :edit] [subject activity])
            true
          
            (= [:signature :edit] [subject activity])
            true
          
          
            (= [:invoice :create] [subject activity])
            true
          
            (= [:invoice :pay] [subject activity])
            true
          
            (= [:invoice :edit] [subject activity])
            true
          
            (= [:invoice :delete] [subject activity])
            true
          
            (= [:ledger :read] [subject activity])
            true

            (= [:balance-sheet :read] [subject activity])
            true

            :else false)

          :else
          false)))

#? (:clj
   (defn wrap-must [handler policy] 
     (fn [request]
       (if (can? (:identity request) policy)
         (handler request)
         {:status  302
         :headers {"Location" (str "/login?"
                                   (url/map->query {"redirect-to" (:uri request)}))}}))))

