(ns auto-ap.datomic.vendors
  (:require [datomic.api :as d]
            [auto-ap.graphql.utils :refer [limited-clients ]]

            [auto-ap.datomic :refer [uri conn merge-query]]))
(defn <-datomic [a]
  (cond-> a
    (:vendor/legal-entity-tin-type a) (update :vendor/legal-entity-tin-type :db/ident)
    (:vendor/legal-entity-1099-type a) (update :vendor/legal-entity-1099-type :db/ident)
    true (assoc :usage (:vendor-usage/_vendor a))
    true (dissoc :vendor-usage/_vendor )))

(defn cleanse [id vendor]
  (let [clients (if-let [clients (limited-clients id)]
                  (set (map :db/id clients))
                  nil)]
    (if clients
      (-> vendor 
          (update :vendor/account-overrides (fn [ao] (filter #(clients (:db/id (:vendor-account-override/client %))) ao)))
          (update :vendor/terms-overrides (fn [to] (filter #(clients (:db/id (:vendor-terms-override/client %))) to)))
          (update :vendor/schedule-payment-dom (fn [to] (filter #(clients (:db/id (:vendor-schedule-payment-dom/client %))) to))))
      vendor)))

(def default-read
  '[* {:vendor/account-overrides [* {:vendor-account-override/client [:client/name :db/id]
                                    :vendor-account-override/account [:account/name :account/numeric-code :db/id]}]
       :vendor/terms-overrides [* {:vendor-terms-override/client [:client/name :client/code :db/id]}]
       :vendor/schedule-payment-dom [* {:vendor-schedule-payment-dom/client [:client/name :client/code :db/id]}]
       :vendor/automatically-paid-when-due [:db/id :client/name]
       :vendor/legal-entity-tin-type [:db/ident :db/id]
       :vendor/legal-entity-1099-type [:db/ident :db/id]
       :vendor/default-account [:db/id :account/numeric-code :account/name]
       :vendor-usage/_vendor [:vendor-usage/client :vendor-usage/count]}])

(defn get-usages [args]
  (->> (cond-> {:query {:find ['?v '?c '(count ?e)]
                        :in ['$]
                        :where ['[?v :vendor/name]
                                '(or-join [?v ?c ?e]
                                          (and 
                                           [?e :invoice/vendor ?v]
                                           [?e :invoice/client ?c])
                                          (and
                                           [?e :transaction/vendor ?v]
                                           [?e :transaction/client ?c])
                                          (and
                                           [?e :journal-entry/vendor ?v]
                                           [?e :journal-entry/client ?c]))]}
                :args [(d/db conn)]}

         (limited-clients (:id args))
         (merge-query {:query {:in ['?xx]
                               :where [['(get ?xx ?c)]]}
                       :args [(set (map :db/id (limited-clients (:id args))))]}))
       (d/query)
       (reduce 
        (fn [usages [v c cnt]]
          (update usages v (fnil conj []) {:client-id c :count cnt}))
        {})))

(defn trim-usage [v limited-clients]
  (->> (if limited-clients
          (update v :usage (fn [usages]
                             (->> usages 
                                  (filter (comp (set (map :db/id limited-clients)) :db/id :vendor-usage/client))
                                  (map (fn [u] {:client-id (:db/id (:vendor-usage/client u))
                                                :count (:vendor-usage/count u)})))))

          (update v :usage (fn [usages]
                             (->> usages 
                                  (map (fn [u] {:client-id (:db/id (:vendor-usage/client u))
                                                :count (:vendor-usage/count u)}))))))

       ))

(defn get-graphql [args]
  (->> (cond-> {:query {:find [(list 'pull '?e default-read)]
                        :in ['$]
                        :where ['[?e :vendor/name]]}
                :args [(d/db (d/connect uri))]})
       (d/query)
       (map first)
       (map #(cleanse (:id args) %))
       (map <-datomic)
       (map #(trim-usage %  (limited-clients (:id args))))
       #_(map #(assoc % :usage (get usages (:db/id %))))))

(defn get-by-id [id]
  
  (->> (d/q '[:find (pull ?e [*
                              {:default-account [:account/name :db/id :account/location]
                               :vendor/legal-entity-tin-type [:db/ident :db/id]
                               :vendor/legal-entity-1099-type [:db/ident :db/id]
                               :vendor/account-overrides [* {:vendor-account-override/client [:client/name :db/id]
                                                             :vendor-account-override/account [:account/name :account/numeric-code :db/id]}]
                               :vendor/terms-overrides [* {:vendor-terms-override/client [:client/name :db/id]}]
                               :vendor/schedule-payment-dom [* {:vendor-schedule-payment-dom/client [:client/name :db/id]}]
                               :vendor/automatically-paid-when-due [:db/id :client/name]}])
              :in $ ?e
              :where [?e]]
            (d/db (d/connect uri))
            id)
       (map first)
       (map <-datomic)
       (first)))


(defn terms-for-client-id [vendor client-id]
  (or
   (->> 
    (filter
     (fn [to]
       (= (:db/id (:vendor-terms-override/client to))
          client-id))
     (:vendor/terms-overrides vendor))
    first
    :vendor-terms-override/terms)
   (:vendor/terms vendor)))

(defn account-for-client-id [vendor client-id]
  (or 
   (->> 
    (filter
     (fn [to]
       (= (:db/id (:vendor-account-override/client to))
          client-id))
     (:vendor/account-overrides vendor))
    first
    :vendor-account-override/account)
   (:vendor/default-account vendor)))

(defn automatically-paid-for-client-id? [vendor client-id]
  (->> 
   (:vendor/automatically-paid-when-due vendor)
   (filter
    (fn [client]
      (= (:db/id client)
         client-id)))
   first
   boolean))
