(ns auto-ap.datomic.invoices
  (:require [datomic.api :as d]
            [auto-ap.datomic :refer [uri remove-nils]]
            [auto-ap.graphql.utils :refer [limited-clients]]
            [auto-ap.parse :as parse]
            [clj-time.coerce :as c]
            [clojure.set :refer [rename-keys]]
            [clojure.string :as str]))


(defn add-arg [query name value where & rest]
  (let [query (-> query
                  (update :args conj value)
                  (update-in [:query :in] conj name)
                  (update-in [:query :where] conj where))]
    (reduce #(update-in %1 [:query :where] conj %2) query rest)))

(def default-read '(pull ?e [*
                             {:invoice/client [:client/name :db/id :client/locations :client/code]}
                             {:invoice/vendor [* {:vendor/address [*]}]}
                             {:invoice/status [:db/ident]}
                             {:invoice-payment/_invoice [* {:invoice-payment/payment [* {:payment/status [*]}
                                                                                      {:payment/bank-account [*]}
                                                                                      {:transaction/_payment [*]}]}]}]))

(defn <-datomic [x]
  (->> x
       
       
       (map #(update % :invoice/date c/from-date))
       (map #(update % :invoice/status :db/ident))
       (map #(rename-keys % {:invoice-payment/_invoice :invoice/payments}))))

(defn raw-graphql [args]
  (->> (d/query
        (cond-> {:query {:find [default-read]
                         :in ['$]
                         :where ['[?e :invoice/invoice-number]]}
                 :args [(d/db (d/connect uri))]}

          (limited-clients (:id args)) (add-arg '[?xx ...] (set (map :db/id (limited-clients (:id args))))
                                                '[?e :invoice/client ?xx])
          (:client-id args) (add-arg '?client-id (:client-id args)
                                     '[?e :invoice/client ?client-id])

          (:client-code args) (add-arg '?client-code (:client-code args)
                                       '[?e :invoice/client ?client-id]
                                       '[?client-id :client/code ?client-code])

          (:original-id args) (add-arg '?original-id (cond-> (:original-id args) (string? (:original-id args)) Long/parseLong )
                                       '[?e :invoice/client ?c]
                                       '[?c :client/original-id ?original-id]) 
          (:import-status args) (add-arg '?import-status (keyword "import-status" (:import-status args))
                                  '[?e :invoice/import-status ?import-status])
          (:status args) (add-arg '?status (keyword "invoice-status" (:status args))
                                  '[?e :invoice/status ?status])
          (:vendor-id args) (add-arg '?vendor-id (:vendor-id args)
                                     '[?e :invoice/vendor ?vendor-id])
          (seq (:invoice-number-like args)) (add-arg '?invoice-number-like (:invoice-number-like args)
                                               '[?e :invoice/invoice-number ?invoice-number]
                                               '[(.contains ^String ?invoice-number ?invoice-number-like)])))
       (map first)
       (<-datomic)))

(defn sort-fn  [args]
  (cond
    (= "client" (:sort-by args))
    #(-> % :invoice/client :client/name .toLowerCase)

    (= "vendor" (:sort-by args))
    #(-> % :invoice/vendor :vendor/name .toLowerCase)

    :else
    (keyword "invoice" (:sort-by args))))

(defn get-graphql [args]
  (let [results (raw-graphql args)]
    (cond->> results
      (:sort-by args) (sort-by (sort-fn args))
      (= (:asc args) false) (reverse)
      true (drop (:start args 0))
      true (take (:count args 100)))))

(defn count-graphql [args]
  
  (->> (raw-graphql args)
       (count)))

(defn get-by-id [id]
  (->> 
   (d/query (-> {:query {:find [default-read]
                         :in ['$]
                         :where []}
                 :args [(d/db (d/connect uri))]}
                (add-arg '?e id ['?e])))
   (map first)
   (<-datomic)   
   (first)))

(defn update [update]
  @(d/transact (d/connect uri) [update])
  (get-by-id (:db/id update) ))

(defn get-multi [ids]
  (->> 
   (d/query {:query {:find [[default-read '...]]
                     :in ['$ ['?e '...]]
                     :where [['?e]]}
             :args [(d/db (d/connect uri))
                    ids] } 

         
         )
   (<-datomic)))



(defn find-conflicting [{:keys [:invoice/invoice-number :invoice/vendor :invoice/client :db/id]}]
  
  (->> (d/query
        (cond-> {:query {:find [default-read]
                         :in ['$ '?invoice-number '?vendor '?client '?invoice-id]
                         :where '[[?e :invoice/invoice-number ?invoice-number]
                                  [?e :invoice/vendor ?vendor]
                                  [?e :invoice/client ?client]
                                  [(not= ?e ?invoice-id)]
                                  ]}
                 
                 :args [(d/db (d/connect uri)) invoice-number vendor client (or id 0)]}))
       (map first)
       
       (<-datomic)))


