(ns auto-ap.datomic.sales-orders
  (:require [auto-ap.datomic :refer [add-sorter-fields apply-pagination apply-sort-3 merge-query uri]]
            [auto-ap.graphql.utils :refer [limited-clients]]
            [auto-ap.utils :refer [dollars=]]
            [clj-time.coerce :as c]
            [datomic.api :as d]
            [clojure.tools.logging :as log]))

(defn <-datomic [result]
  (-> result
      (update :sales-order/date c/from-date)
      (update :sales-order/charges (fn [cs]
                                     (map (fn [c]
                                            (update c :charge/processor :db/ident))
                                          cs)))))

(def default-read '[*
                    {:sales-order/client [:client/name :db/id :client/code]
                     :sales-order/charges [* {:charge/processor [:db/ident]}]}])

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

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

                (:client-id args)
                (merge-query {:query {:in ['?client-id]
                                      :where ['[?e :sales-order/client ?client-id]]}
                              :args [(:client-id args)]})
                (:client-code args)
                (merge-query {:query {:in ['?client-code]
                                      :where ['[?e :sales-order/client ?client-id]
                                              '[?client-id :client/code ?client-code]]}
                              :args [(:client-code args)]})
                
                (:processor args)
                (merge-query {:query {:in ['?processor]
                                      :where ['[?e :sales-order/charges ?chg]
                                              '[?chg :charge/processor ?processor]]}
                              :args [(keyword "ccp-processor"
                                              (name (:processor args)))]})

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

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

                (:total args)
                (merge-query {:query {:in ['?total]
                                      :where ['[?e :sales-order/total ?sales-order-total]
                                              '[(auto-ap.utils/dollars= ?sales-order-total ?total)]]}
                              :args [(:total args)]})

                
                (:start (:date-range args))
                (merge-query {:query {:in '[?start-date]
                                      :where ['[?e :sales-order/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 :sales-order/date ?date]
                                              '[(<= ?date ?end-date)]]}
                              :args [(c/to-date (:end (:date-range args)))]})

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

(defn graphql-results [ids db args]
  (let [results (->> (d/pull-many db default-read ids)
                     (group-by :db/id))
        payments (->> ids
                     (map results)
                     (map first)
                     (mapv <-datomic))]
    payments))

(defn summarize-orders [ids]

  (let [[total tax] (->>
         (d/query {:query {:find ['(sum ?t) '(sum ?tax)]
                           :with ['?id]
                           :in ['$ '[?id ...]]
                           :where ['[?id :sales-order/total ?t]
                                   '[?id :sales-order/tax ?tax]]}
                   :args [(d/db (d/connect uri))
                          ids]})
         first)]
    {:total total
     :tax tax}))

(defn get-graphql [args]
  (log/info "ARGS" args)
  (let [db (d/db (d/connect uri))
        {ids-to-retrieve :ids matching-count :count} (raw-graphql-ids db args)]

    [(->> (graphql-results ids-to-retrieve db args))
     matching-count
     (summarize-orders ids-to-retrieve)]))

(defn get-by-id [id]
  (->> 
   (d/pull (d/db (d/connect uri)) default-read id)
   (<-datomic)))
