(ns auto-ap.datomic.expected-deposit
  (:require
   [auto-ap.datomic
    :refer [add-sorter-fields
            apply-pagination
            apply-sort-3
            conn
            merge-query
            pull-many
            query2]]
   [auto-ap.graphql.utils :refer [limited-clients]]
   [clj-time.coerce :as c]
   [datomic.api :as dc]))

(defn <-datomic [result]
  (let [transaction (first (:transaction/_expected-deposit result))
        transaction (when transaction
                      (update transaction :transaction/date c/from-date))]
    (cond-> result
      true        (update :expected-deposit/date c/from-date)
      transaction (assoc :transaction transaction))))

(def default-read '[*
                    {:expected-deposit/client [:client/name :db/id :client/code]
                     :expected-deposit/status [:db/ident]
                     :transaction/_expected-deposit [:transaction/date :db/id]}])

(defn raw-graphql-ids [db args]
  (let [query (cond-> {:query {:find []
                               :in ['$]
                               :where []}
                       :args [db]}
                (:sort args) (add-sorter-fields {"client" ['[?e :expected-deposit/client ?c]
                                                           '[?c :client/name ?sort-client]]
                                                 "location" ['[?e :expected-deposit/location ?sort-location]]
                                                 "date" ['[?e :expected-deposit/date ?sort-date]]
                                                 "total" ['[?e :expected-deposit/total ?sort-total]]
                                                 "fee" ['[?e :expected-deposit/fee ?sort-fee]]}
                                                  args)

                true
                (merge-query {:query {:in    ['[?xx ...]]
                                      :where ['[?e :expected-deposit/client ?xx]]}
                              :args  [(set (map :db/id (:clients args)))]})

                (:exact-match-id args)
                (merge-query {:query {:in ['?e]
                                      :where []}
                              :args [(:exact-match-id args)]})

                (:client-id args)
                (merge-query {:query {:in ['?client-id]
                                      :where ['[?e :expected-deposit/client ?client-id]]}
                              :args [(:client-id args)]})
                (:client-code args)
                (merge-query {:query {:in ['?client-code]
                                      :where ['[?e :expected-deposit/client ?client-id]
                                              '[?client-id :client/code ?client-code]]}
                              :args [(:client-code args)]})

                (:total-gte args) 
                (merge-query {:query {:in ['?total-gte]
                                      :where ['[?e :expected-deposit/total ?a]
                                              '[(>= ?a ?total-gte)]]}
                              :args [(:total-gte args)]})

                (:total-lte args) 
                (merge-query {:query {:in ['?total-lte]
                                      :where ['[?e :expected-deposit/total ?a]
                                              '[(<= ?a ?total-lte)]]}
                              :args [(:total-lte args)]})

                (:total args)
                (merge-query {:query {:in ['?total]
                                      :where ['[?e :expected-deposit/total ?expected-deposit-total]
                                              '[(iol-ion.query/dollars= ?expected-deposit-total ?total)]]}
                              :args [(:total args)]})

                
                (:start (:date-range args))
                (merge-query {:query {:in '[?start-date]
                                      :where ['[?e :expected-deposit/date ?date]
                                              '[(>= ?date ?start-date)]]}
                              :args [(c/to-date (:start (:date-range args)))]})

                (:end (:date-range args))
                (merge-query {:query {:in '[?end-date]
                                      :where ['[?e :expected-deposit/date ?date]
                                              '[(<= ?date ?end-date)]]}
                              :args [(c/to-date (:end (:date-range args)))]})

                true
                (merge-query {:query {:find ['?sort-default '?e]
                                      :where ['[?e :expected-deposit/date ?sort-default]]}}))]
    
    (cond->> (query2 query)
      true (apply-sort-3 args)
      true (apply-pagination args))))

(defn graphql-results [ids db _]
  (let [results (->> (pull-many db default-read ids)
                     (group-by :db/id))
        payments (->> ids
                     (map results)
                     (map first)
                     (mapv <-datomic)
                     (map (fn get-totals [ed]
                            (assoc ed :totals
                                   (->> (dc/q '[:find ?d4 (count ?c) (sum ?a)
                                               :in $ ?ed
                                               :where [?ed :expected-deposit/charges ?c]
                                               [?c :charge/total ?a]
                                               [?o :sales-order/charges ?c]
                                               [?o :sales-order/date ?d]
                                               [(clj-time.coerce/from-date ?d) ?d2]
                                               [(auto-ap.time/localize ?d2) ?d3]
                                               [(clj-time.coerce/to-local-date ?d3) ?d4]]
                                             (dc/db conn)
                                             (:db/id ed))
                                        (map (fn [[date count amount]]
                                               {:date (c/to-date-time date)
                                                :count count
                                                :amount amount})))))))]
    payments))

(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]))
