(ns auto-ap.datomic.vendors
  (:require
   [auto-ap.datomic
    :refer [add-sorter-fields
            apply-pagination
            apply-sort-3
            conn
            merge-query
            pull-many
            query2]]
   [auto-ap.datomic.accounts :as d-accounts]
   [auto-ap.graphql.utils :refer [limited-clients]]
   [clojure.string :as str]
   [datomic.api :as dc]))

(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 [aos]
                                              (->>  aos
                                                    (filter #(clients (:db/id (:vendor-account-override/client %))))
                                                    (map #(update % :vendor-account-override/account d-accounts/clientize (:db/id (:vendor-account-override/client %)))))))
          (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 
          (update :vendor/account-overrides (fn [aos]
                                              (->>  aos
                                                    (map #(update % :vendor-account-override/account d-accounts/clientize (:db/id (:vendor-account-override/client %)))))))))))

(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
                                                                       {:account/client-overrides [:account-client-override/client :account-client-override/name]}]}]
       :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/plaid-merchant [:db/id :plaid-merchant/name]
       :vendor-usage/_vendor               [:vendor-usage/client :vendor-usage/count]}])


(defn raw-graphql-ids [db args]
  (let [query (cond-> {:query {:find []
                               :in ['$]
                               :where []}
                       :args [db]}
                (:sort args) (add-sorter-fields {"name" ['[?e :vendor/name ?sort-name]]}
                                                  args)

                (not (str/blank? (:name-like args)))
                (merge-query {:query {:in ['?name-like]
                                      :where ['[?e :vendor/name ?n]
                                              '[(re-pattern ?name-like) ?name-like-2]
                                              '[(re-find ?name-like-2 ?n)]]}
                              :args [(str "(?i)"  (:name-like args))]})

                true
                (merge-query {:query {:find ['?e]
                                      :where ['[?e :vendor/name]]}}))]

    
    (cond->> (query2 query)
      true (apply-sort-3 args)
      true (apply-pagination args))))

(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 graphql-results [ids db args]
  (let [results (->> (pull-many db default-read ids)
                     (group-by :db/id))
        vendors (->> ids
                     (map results)
                     (map first)
                     (map #(cleanse (:id args) %))
                     (map <-datomic))]
    vendors))

(defn get-graphql [args]
  (let [db                                           (dc/db conn)
        {ids-to-retrieve :ids matching-count :count} (raw-graphql-ids db args)]
    [(->> (graphql-results ids-to-retrieve db args))
     matching-count])

  )

(defn get-graphql-by-id [args id]
  (->> (dc/q {:find  [(list 'pull '?e default-read)]
              :in    ['$ '?e]
              :where ['[?e :vendor/name]]}
             (dc/db conn) id)
       (map first)
       (map #(cleanse (:id args) %))
       (map <-datomic)
       (map #(trim-usage %  (limited-clients (:id args))))
       first))

(defn get-by-id [id]
  
  (->> (dc/q '[:find (pull ?e [*
                              {:vendor/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/plaid-merchant [:db/id :plaid-merchant/name]
                               :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]]
            (dc/db conn)
            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))


