(ns auto-ap.graphql.clients
  (:require
   [amazonica.aws.s3 :as s3]
   [auto-ap.datomic :refer [audit-transact conn]]
   [auto-ap.datomic.clients :as d-clients]
   [iol-ion.tx :refer [upsert-entity]]
   [auto-ap.graphql.utils
    :refer [->graphql
            assert-admin
            attach-tracing-resolvers
            can-see-client?
            is-admin?]]
   [auto-ap.routes.queries :as q]
   [auto-ap.square.core :as square]
   [auto-ap.utils :refer [heartbeat]]
   [clj-time.coerce :as coerce]
   [clojure.java.io :as io]
   [clojure.set :as set]
   [clojure.string :as str]
   [clojure.tools.logging :as log]
   [datomic.client.api :as dc]
   [unilog.context :as lc]
   [mount.core :as mount]
   [yang.scheduler :as scheduler]
   [iol-ion.tx :refer [random-tempid]]
   [com.brunobonacci.mulog :as mu])
  (:import
   (java.util UUID)
   (org.apache.commons.codec.binary Base64)))

(defn assert-client-code-is-unique [code]
  (when (seq (dc/q {:query {:find  '[?id]
                            :in    ['$ '?code]
                            :where ['[?id :client/code ?code]]}
                    :args  [(dc/db conn) code]}))
    (throw (ex-info "Client is not unique" {:validation-error (str "Client code '" code "' is not unique.")}))))

(defn upload-signature-data [signature-data]
  (let [prefix "data:image/jpeg;base64,"]
    (when signature-data
      (when-not (str/starts-with? signature-data prefix)
        (throw (ex-info "Invalid signature image" {:validation-error (str "Invalid signature image.")})))
      (let [signature-id (str (UUID/randomUUID))
            raw-bytes (Base64/decodeBase64 (subs signature-data (count prefix)))]
        (s3/put-object :bucket-name "integreat-signature-images" #_(:data-bucket env)
                       :key (str signature-id ".jpg")
                       :input-stream (io/make-input-stream raw-bytes {})
                       :metadata {:content-type "image/jpeg"
                                  :content-length (count raw-bytes)}
                       :canned-acl "public-read")
        (str "https://integreat-signature-images.s3.amazonaws.com/" signature-id ".jpg")))))

(defn assert-no-shared-transaction-sources [client-code txes]
  (let [new-db (:db-after (dc/with (dc/with-db conn)
                                   {:tx-data txes}))]
    (when (seq (->> (dc/q '[:find ?src (count ?ba) 
                           :in $ ?c
                           :where [?c :client/bank-accounts ?ba]
                           (or 
                            [?ba :bank-account/intuit-bank-account ?src]
                            [?ba :bank-account/plaid-account ?src]
                            [?ba :bank-account/yodlee-account-id ?src])]
                         new-db [:client/code client-code])
                    (filter (fn [[_ cnt]]
                              (> cnt 1)))))
      (throw (ex-info "Cannot reuse yodlee/plaid/intuit account" {:validation-error (str "Cannot reuse yodlee/plaid/intuit account")})))))

(defn edit-client [context {:keys [edit_client]} _]
  (assert-admin (:id context))
  (when-not (:id edit_client)
    (assert-client-code-is-unique (:code edit_client)))
 
  (let [client (when (:id edit_client) (d-clients/get-by-id (:id edit_client)))
        id (or (:db/id client) "new-client")
        signature-file (upload-signature-data (:signature_data edit_client))
        client-code (if (str/blank? (:client/code client))
                      (:code edit_client)
                      (:client/code client))
        updated-entity {:db/id                    id
                        :client/code              client-code
                        :client/name              (:name edit_client)
                        :client/matches           (:matches edit_client)
                        :client/signature-file    signature-file
                        :client/email             (:email edit_client)
                        :client/locked-until      (some-> (:locked_until edit_client) (coerce/to-date))
                        :client/locations         (filter identity (:locations edit_client))
                        :client/week-a-debits     (:week_a_debits edit_client)
                        :client/week-a-credits    (:week_a_credits edit_client)
                        :client/week-b-debits     (:week_b_debits edit_client)
                        :client/square-auth-token (:square_auth_token edit_client)
                        :client/square-locations  (map
                                                    (fn [sl]
                                                      {:db/id                           (or (:id sl) (random-tempid))
                                                       :square-location/client-location (:client_location sl)})
                                                    (:square_locations edit_client))

                        :client/emails            (map (fn [e]
                                                         {:db/id                     (or (:id e)
                                                                                         (random-tempid))
                                                          :email-contact/email       (:email e)
                                                          :email-contact/description (:description e)})
                                                       (:emails edit_client))

                        :client/feature-flags (:feature_flags edit_client)
                        :client/ezcater-locations (map
                                                    (fn [el]
                                                      {:db/id                     (or (:id el) (random-tempid))
                                                       :ezcater-location/location (:location el)
                                                       :ezcater-location/caterer  (:caterer el)})
                                                    (:ezcater_locations edit_client))
                        :client/week-b-credits    (:week_b_credits edit_client)
                        :client/location-matches  (->> (:location_matches edit_client)
                                                       (filter (fn [lm] (and (:location lm) (:match lm))))
                                                       (map (fn [lm] {:db/id (or (:id lm ) (random-tempid))
                                                                      :location-match/location (:location lm)
                                                                      :location-match/matches  [(:match lm)]})))
                        :client/address           (when (seq (filter identity (vals (:address edit_client))))
                                                    {:db/id           (or (:id (:address edit_client)) (random-tempid))
                                                     :address/street1 (:street1 (:address edit_client))
                                                     :address/street2 (:street2 (:address edit_client))
                                                     :address/city    (:city (:address edit_client))
                                                     :address/state   (:state (:address edit_client))
                                                     :address/zip     (:zip (:address edit_client))})
                        :client/bank-accounts     (map (fn [ba]
                                                         {:db/id                           (or (:id ba) (random-tempid))
                                                          :bank-account/code               (:code ba)
                                                          :bank-account/bank-name          (:bank_name ba)
                                                          :bank-account/bank-code          (:bank_code ba)
                                                          :bank-account/start-date         (-> (:start_date ba) (coerce/to-date))
                                                          :bank-account/routing            (:routing ba)
                                                          :bank-account/include-in-reports (:include_in_reports ba)

                                                          :bank-account/name                           (:name ba)
                                                          :bank-account/visible                        (:visible ba)
                                                          :bank-account/number                         (:number ba)
                                                          :bank-account/check-number                   (:check_number ba)
                                                          :bank-account/numeric-code                   (:numeric_code ba)
                                                          :bank-account/sort-order                     (:sort_order ba)
                                                          :bank-account/locations                      (:locations ba)
                                                          :bank-account/use-date-instead-of-post-date? (boolean (:use_date_instead_of_post_date ba))

                                                          :bank-account/yodlee-account-id   (:yodlee_account_id ba)
                                                          :bank-account/type                (keyword "bank-account-type" (name (:type ba)))
                                                          :bank-account/yodlee-account      (when (:yodlee_account ba)
                                                                                              [:yodlee-account/id (:yodlee_account ba)])
                                                          :bank-account/plaid-account       (:plaid_account ba)
                                                          :bank-account/intuit-bank-account (:intuit_bank_account ba)})
                                                       (:bank_accounts edit_client))

                        }
        _ (mu/log ::upserting :up updated-entity)
        _ (assert-no-shared-transaction-sources client-code [`(upsert-entity ~updated-entity)])
        _ (log/info "upserting client" updated-entity)
        
        result (audit-transact [`(upsert-entity ~updated-entity)] (:id context))]
    (when (:square_auth_token edit_client)
      (square/upsert-locations (-> result :tempids (get id) (or id) d-clients/get-by-id)))
    (-> (-> result :tempids (get id) (or id) d-clients/get-by-id)

        (update :client/bank-accounts 
                (fn [bas]
                  (map #(set/rename-keys % {:bank-account/use-date-instead-of-post-date? :use-date-instead-of-post-date}) bas)))
        (update :client/location-matches
                (fn [lms]
                  (mapcat (fn [lm]
                            (map (fn [m]
                                      {:location-match/match m
                                       :location-match/location (:location-match/location lm)})
                                    (:location-match/matches lm)))
                          lms)))
        ->graphql)))

(defn refresh-bank-account-current-balance [bank-account-id]
  (let [all-transactions (dc/q 
                          {:query {:find ['?e '?debit '?credit]
                                   :in ['$ '?bank-account-id]
                                   :where '[[?e :journal-entry-line/account ?bank-account-id]
                                            [(get-else $ ?e :journal-entry-line/debit 0.0) ?debit]
                                            [(get-else $ ?e :journal-entry-line/credit 0.0) ?credit]]}
                           :args [(dc/db conn) bank-account-id]})
        debits (->> all-transactions
                    (map (fn [[_ debit _]]
                           debit))
                    (reduce + 0.0))
        credits (->> all-transactions
                     (map (fn [[_ _ credit]]
                            credit))
                     (reduce + 0.0))
        current-balance (if (= :bank-account-type/check (:db/ident (:bank-account/type (dc/pull (dc/db conn) [:bank-account/type] bank-account-id))))
                          (- debits credits)
                          (- credits debits))]
    (dc/transact conn {:tx-data [{:db/id                        bank-account-id
                                  :bank-account/current-balance current-balance}]})))

(defn bank-accounts-needing-refresh []
  (let [last-refreshed (->> (dc/q {:query {:find ['?ba '?tx]
                                      :in ['$ ]
                                      :where ['[?ba :bank-account/current-balance _ ?tx true]]}
                              :args [(dc/history (dc/db conn))]})
                            (group-by first)
                            (map (fn [[ba balance-txes]]
                                   [ba (->> balance-txes
                                         (map second)
                                         (sort-by #(- %))
                                         first)])))
        has-newer-transaction (->> (dc/q
                                 {:query {:find ['?ba]
                                          :in '[$ [[?ba ?last-refreshed] ...] ]
                                          :where ['[_ :journal-entry-line/account ?ba ?tx]
                                                  '[(>= ?tx ?last-refreshed)]]}
                                  :args [(dc/history (dc/db conn))
                                         last-refreshed]})
                                (map first)
                                (set))

        no-current-balance (->> (dc/q {:query {:find ['?ba]
                                                  :in '[$]
                                                  :where ['[?ba :bank-account/code]
                                                          '(not [?ba :bank-account/current-balance])
                                                          ]}
                                          :args [(dc/db conn)]})
                                (map first))]
    (into has-newer-transaction no-current-balance)))

(defn build-current-balance [bank-accounts]
  (doseq [bank-account bank-accounts]
    (log/info "Refreshing bank account" (-> (dc/db conn) (dc/pull [:bank-account/code] bank-account)))
    (try 
      (refresh-bank-account-current-balance bank-account)
      (catch Exception e
        (log/error "Can't refresh current balance" e)))))

#_{:clj-kondo/ignore [:clojure-lsp/unused-public-var]}
(defn refresh-all-current-balance []
  (lc/with-context {:source "current-balance-cache"}
    (build-current-balance (->> (dc/q {:query {:find  ['?ba]
                                               :in    '[$]
                                               :where ['[?ba :bank-account/code]]}
                                       :args  [(dc/db conn)]})
                                (map first)))))

(defn refresh-current-balance []
  (build-current-balance (bank-accounts-needing-refresh)))

(defn get-client [context _ _]
  (->graphql
   (->> (d-clients/get-all)
        (filter #(can-see-client? (:id context) %))
        (map (fn [c]
               (update c :client/bank-accounts (fn [bas]
                                                 (map #(set/rename-keys % {:bank-account/use-date-instead-of-post-date? :use-date-instead-of-post-date}) bas)))))
        (map (fn [c]
               (if (is-admin? (:id context))
                 c
                 (-> c
                     (dissoc :client/yodlee-provider-accounts)
                     (dissoc :client/plaid-items)))))
        (map (fn [c]
               (update c :client/bank-accounts
                       (fn [bank-accounts]
                         (mapv (fn [ba]
                                 (assoc ba :bank-account/yodlee-balance-old nil))
                               bank-accounts))))))))



(def sales-summary-query
  "[:find ?d4 (sum ?total) (sum ?tax) (sum ?tip)  (sum ?service-charge) (sum ?discount) (sum ?returns)
  :with ?s
  :in $
  :where
  [?s :sales-order/client [:client/code \"%s\"]]
[(ground (clj-time.coerce/to-date (clj-time.core/minus (auto-ap.time/local-now) (clj-time.core/days 90)))) ?min-d]
[?s :sales-order/date ?d]
[(>= ?d ?min-d)]
[?s :sales-order/total ?total]
[?s :sales-order/tax ?tax]
[?s :sales-order/tip ?tip]
[?s :sales-order/service-charge ?service-charge]
[?s :sales-order/returns ?returns]
[?s :sales-order/discount ?discount]
[(clj-time.coerce/to-date-time ?d) ?d2]
[(auto-ap.time/localize ?d2) ?d3]
[(auto-ap.time/unparse-local ?d3 auto-ap.time/normal-date) ?d4]
]")

(def sales-category-query
  "[:find  ?d4 ?n ?n2 (sum ?total) (sum ?tax) (sum ?discount)
  :with ?s ?li
  :in $ 
  :where 
  [?s :sales-order/client [:client/code \"%s\"]]
  [(ground (clj-time.coerce/to-date (clj-time.core/minus (auto-ap.time/local-now) (clj-time.core/days 90)))) ?min-d]
  [?s :sales-order/date ?d]
  [(>= ?d ?min-d)]
  [?s :sales-order/line-items ?li]
  [?li :order-line-item/category ?n]
  [(get-else $ ?li :order-line-item/item-name \"\") ?n2]
[?li :order-line-item/total ?total]
[?li :order-line-item/tax ?tax]
[?li :order-line-item/discount ?discount]
[(clj-time.coerce/to-date-time ?d) ?d2]
[(auto-ap.time/localize ?d2) ?d3]
[(auto-ap.time/unparse-local ?d3 auto-ap.time/normal-date) ?d4]
]")

(def expected-deposits-query
  "[:find ?d4 ?t ?f
:in $ 
:where 
  [?c :client/code \"%s\"]
[?s :expected-deposit/client ?c]
[?s :expected-deposit/total ?t]
[?s :expected-deposit/fee ?f]
[?s :expected-deposit/sales-date ?date]
[(clj-time.coerce/to-date-time ?date) ?d2]
[(auto-ap.time/localize ?d2) ?d3]
[(auto-ap.time/unparse-local ?d3 auto-ap.time/normal-date) ?d4]
]")

(def tenders-query
  "[:find ?d4 ?type ?p2 (sum ?total) (sum ?tip)
:with ?charge
:in $
:where
  [?c :client/code \"%s\"]
[?s :sales-order/client ?c]
[(ground (clj-time.coerce/to-date (clj-time.core/minus (auto-ap.time/local-now) (clj-time.core/days 90)))) ?min-d]
[?s :sales-order/date ?date]
[(>= ?date ?min-d)]
[?s :sales-order/charges ?charge]
[?charge :charge/type-name ?type]
[?charge :charge/total ?total]
[?charge :charge/tip ?tip]
[(get-else $ ?charge :charge/processor :na) ?ccp]
[(get-else $ ?ccp :db/ident :na) ?p]
[(name ?p) ?p2]
[(clj-time.coerce/to-date-time ?date) ?d2]
[(auto-ap.time/localize ?d2) ?d3]
[(auto-ap.time/unparse-local ?d3 auto-ap.time/normal-date) ?d4]
]")

(def tenders2-query
  "[:find ?d4 ?type ?p2 (sum ?total) (sum ?tip)
   :with ?charge
   :in $
   :where
   [?charge :charge/date ?date]
   [(ground (clj-time.coerce/to-date (clj-time.core/minus (auto-ap.time/local-now) (clj-time.core/days 90)))) ?min-d]
   [(>= ?date ?min-d)]
   [?charge :charge/client ?c]
   [?c :client/code \"%s\"]
   [?charge :charge/type-name ?type]
   [?charge :charge/total ?total]
   [?charge :charge/tip ?tip]
   (or

     (and [_ :expected-deposit/charges ?charge ]
          [(ground :settlement) ?ccp]
          [(ground :settlement) ?p])
     (and 
       (not [_ :expected-deposit/charges ?charge])
       [(get-else $ ?charge :charge/processor :na) ?ccp]
       [(get-else $ ?ccp :db/ident :na) ?p]
       ))
   [(name ?p) ?p2]
   [(clj-time.coerce/to-date-time ?date) ?d2]
   [(auto-ap.time/localize ?d2) ?d3]
   [(auto-ap.time/unparse-local ?d3 auto-ap.time/normal-date) ?d4]]" )

(def refunds-query
  "[:find ?d4 ?t (sum ?total) (sum ?fee)
:with ?r
:in $ 
:where 
  [?r :sales-refund/client [:client/code \"%s\"]]
[?r :sales-refund/total ?total]
[?r :sales-refund/fee ?fee]
[?r :sales-refund/date ?date]
[?r :sales-refund/type ?t]
[(clj-time.coerce/to-date-time ?date) ?d2]
[(auto-ap.time/localize ?d2) ?d3]
[(auto-ap.time/unparse-local ?d3 auto-ap.time/normal-date) ?d4]]")



(defn setup-sales-queries [context args _]
  (assert-admin (:id context))
(let [{client-code :client/code feature-flags :client/feature-flags} (dc/pull (dc/db conn) '[:client/code :client/feature-flags] (:client_id args))
      is-new-square? ((set feature-flags) "new-square")]
    (q/put-query (str (UUID/randomUUID))
                 (format sales-summary-query client-code)
                 (str "sales query for " client-code)
                 (str client-code "-sales-summary")
                 [:client/code client-code]
                 )
    (q/put-query (str (UUID/randomUUID))
                 (format sales-category-query client-code)
                 (str "sales category query for " client-code)
                 (str client-code "-sales-category")
                 [:client/code client-code]
                 )
    (q/put-query (str (UUID/randomUUID))
                 (format expected-deposits-query client-code)
                 (str "expected deposit query for " client-code)
                 (str client-code "-expected-deposit")
                 [:client/code client-code]
                 )
    (q/put-query (str (UUID/randomUUID))
                 (format (if is-new-square? tenders2-query tenders-query) client-code)
                 (str "tender query for " client-code)
                 (str client-code "-tender")
                 [:client/code client-code]
                 )

    (q/put-query (str (UUID/randomUUID))
                 (format refunds-query client-code)
                 (str "refunds query for " client-code)
                 (str client-code "-refund")
                 [:client/code client-code])
    (let [sales-summary-id    (:saved-query/guid (dc/pull (dc/db conn) [:saved-query/guid] [:saved-query/lookup-key (str client-code "-sales-summary")]))
          sales-category-id   (:saved-query/guid (dc/pull (dc/db conn) [:saved-query/guid] [:saved-query/lookup-key (str client-code "-sales-category")]))
          expected-deposit-id (:saved-query/guid (dc/pull (dc/db conn) [:saved-query/guid] [:saved-query/lookup-key (str client-code "-expected-deposit")]))
          tender-id           (:saved-query/guid (dc/pull (dc/db conn) [:saved-query/guid] [:saved-query/lookup-key (str client-code "-tender")]))
          refund-id           (:saved-query/guid (dc/pull (dc/db conn) [:saved-query/guid] [:saved-query/lookup-key (str client-code "-refund")]))]
      {:message (str/join "\n"
                          [
                           (str "For " client-code ":")
                           (str "Sales: " "https://app.integreatconsult.com/api/queries/" sales-summary-id "/results/json")
                           (str "Sales Category: " "https://app.integreatconsult.com/api/queries/" sales-category-id "/results/json")
                           (str "Expected Deposits: " "https://app.integreatconsult.com/api/queries/" expected-deposit-id "/results/json")
                           (str "Tenders: " "https://app.integreatconsult.com/api/queries/" tender-id "/results/json")
                           (str "Refund: " "https://app.integreatconsult.com/api/queries/" refund-id "/results/json")])})))


(def objects
  {:location_match
   {:fields {:location {:type 'String}
             :match {:type 'String}
             :id {:type :id}}}

   :square_location
   {:fields {:client_location {:type 'String}
             :name            {:type 'String}
             :square_id       {:type 'String}
             :id              {:type :id}}}

   :ezcater_location
   {:fields {:location {:type 'String}
             :caterer         {:type :ezcater_caterer}
             :id              {:type :id}}}

   :email_contact {:fields {:id          {:type :id}
                            :email       {:type 'String}
                            :description {:type 'String}}}

   :client
   {:fields {:id {:type :id}
             :name {:type 'String}
             :locked_until {:type :iso_date}
             :code {:type 'String}
             :feature_flags {:type '(list String)}
             :square_auth_token {:type 'String}
             :signature_file {:type 'String}
             :square_integration_status {:type :integration_status}
             :week_a_debits {:type :money}
             :week_a_credits {:type :money}
             :week_b_debits {:type :money}
             :week_b_credits {:type :money}
             :email {:type 'String}
             :emails {:type '(list :email_contact)}
             :address {:type :address}
             :location_matches {:type '(list :location_match)}
             :locations {:type '(list String)}
             :matches {:type '(list String)}
             :bank_accounts {:type '(list :bank_account)}
             :square_locations {:type '(list :square_location)}
             :ezcater_locations {:type '(list :ezcater_location)}
             :forecasted_transactions {:type '(list :forecasted_transaction)}
             :yodlee_provider_accounts {:type '(list :yodlee_provider_account)}
             :plaid_items {:type '(list :plaid_item)}}}

   :bank_account
   {:fields {:id {:type :id}
             :integration_status {:type :integration_status}
             :type {:type :ident}
             :start_date {:type :iso_date}
             :number {:type 'String}
             :numeric_code {:type 'Int}
             :sort_order {:type 'Int}
             :visible {:type 'Boolean}
             :include_in_reports {:type 'Boolean}
             :routing {:type 'String}
             :code {:type 'String}
             :check_number {:type 'Int}
             :name {:type 'String}
             :bank_code {:type 'String}
             :bank_name {:type 'String}
             :current_balance {:type :money}
             :yodlee_balance_old {:type :money}
             :yodlee_account_id {:type 'Int}
             :yodlee_account {:type :yodlee_account}
             :plaid_account {:type :plaid_account}
             :intuit_bank_account {:type :intuit_bank_account}
             :use_date_instead_of_post_date {:type 'Boolean}
             :locations {:type '(list String)}}}

   :forecasted_transaction {:fields {:identifier {:type 'String}
                                     :id {:type :id}
                                     :day_of_month {:type 'Int}
                                     :amount {:type :money}}}

})

(def queries
  {:client {:type '(list :client)
            :resolve :get-client}})

(def mutations
  {:edit_client {:type :client
                 :args {:edit_client {:type :edit_client}}
                 :resolve :mutation/edit-client}
   :setup_sales_queries {:type :message
                         :args {:client_id {:type :id}}
                         :resolve :mutation/setup-sales-queries}})

(def input-objects
  {:edit_location_match {:fields {:location {:type 'String}
                                  :match {:type 'String}
                                  :id {:type :id}}}

   :edit_square_location {:fields {:client_location    {:type 'String}
                                   :id       {:type :id}}}

   :edit_ezcater_location {:fields {:location {:type 'String}
                                    :caterer         {:type :id}
                                    :id              {:type :id}}}

   :edit_forecasted_transaction {:fields {:identifier {:type 'String}
                                          :id {:type :id}
                                          :day_of_month {:type 'Int}
                                          :amount {:type :money}}}
   :edit_email_contact {:fields {:id {:type :id}
                                 :email {:type 'String}
                                 :description {:type 'String}}}
   :edit_client {:fields {:id {:type :id}
                          :name {:type 'String}
                          :locked_until {:type :iso_date}
                          :code {:type 'String}
                          :square_auth_token {:type 'String}
                          :feature_flags {:type '(list String)}
                          :signature_data {:type 'String}
                          :email {:type 'String}
                          :emails {:type '(list :edit_email_contact)}
                          :week_a_credits {:type :money}
                          :week_a_debits {:type :money}
                          :week_b_credits {:type :money}
                          :week_b_debits {:type :money}
                          :address {:type :add_address}
                          :locations {:type '(list String)}
                          :matches {:type '(list String)}
                          :location_matches {:type '(list :edit_location_match)}
                          :square_locations {:type '(list :edit_square_location)}
                          :ezcater_locations {:type '(list :edit_ezcater_location)}
                          :bank_accounts {:type '(list :edit_bank_account)}
                          :forecasted_transactions {:type '(list :edit_forecasted_transaction)}}}

   :edit_bank_account
   {:fields {:id {:type :id}
             :code {:type 'String}
             :type {:type :bank_account_type}
             :start_date {:type :iso_date}
             :number {:type 'String}
             :check_number {:type 'Int}
             :numeric_code {:type 'Int}
             :visible {:type 'Boolean}
             :include_in_reports {:type 'Boolean}
             :sort_order {:type 'Int}
             :name {:type 'String}
             :bank_code {:type 'String}
             :routing {:type 'String}
             :bank_name {:type 'String}
             :locations {:type '(list String)}
             :yodlee_account_id {:type 'Int}
             :use_date_instead_of_post_date {:type 'Boolean}
             :intuit_bank_account {:type :id}
             :plaid_account {:type :id}
             :yodlee_account {:type 'Int}}}})

(def enums
  {:bank_account_type {:values [{:enum-value :check}
                                {:enum-value :credit}
                                {:enum-value :cash}]}})

(def resolvers
  {:get-client get-client
   :mutation/edit-client edit-client
   :mutation/setup-sales-queries setup-sales-queries})


(defn attach [schema]
  (-> 
   (merge-with merge schema
               {:objects objects
                :queries queries
                :mutations mutations
                :input-objects input-objects
                :enums enums})
   (attach-tracing-resolvers resolvers)))

#_{:clj-kondo/ignore [:clojure-lsp/unused-public-var]}
(mount/defstate indexer
  :start (scheduler/every (* 5 60 1000) (heartbeat d-clients/rebuild-search-index "rebuild-search-index"))
  :stop (scheduler/stop indexer))
