(ns auto-ap.datomic.transaction-rules
  (: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]]
   [clojure.string :as str]
   [datomic.api :as dc]))

(defn <-datomic [result]
  result)

(def default-read '[:db/id
                    :transaction-rule/description
                    :transaction-rule/note
                    :transaction-rule/amount-lte
                    :transaction-rule/amount-gte
                    :transaction-rule/dom-lte
                    :transaction-rule/dom-gte
                    :transaction-rule/client-group
                    {:transaction-rule/client [:client/name :db/id :client/code]}
                    {:transaction-rule/bank-account [:db/id :bank-account/name]}
                    {:transaction-rule/yodlee-merchant [:db/id :yodlee-merchant/name :yodlee-merchant/yodlee-id]}
                    {:transaction-rule/transaction-approval-status [:db/id :db/ident]}
                    {:transaction-rule/vendor [:vendor/name :db/id :vendor/default-account]}
                    {:transaction-rule/accounts [:transaction-rule-account/percentage
                                                 :transaction-rule-account/location
                                                 {:transaction-rule-account/account [:account/name :db/id :account/numeric-code :account/location]}
                                                 :db/id]}])

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

                                                 "yodlee-merchant" ['[?e :transaction-rule/yodlee-merchant ?ym]
                                                                    '[?ym :yodlee-merchant/name ?sort-yodlee-merchant]]
                                                 "bank-account" ['[?e :transaction-rule/bank-account ?ba]
                                                                 '[?ba :bank-account/name ?sort-bank-account]]
                                                 "description" ['[?e :transaction-rule/description ?sort-description]]
                                                 "note" ['[?e :transaction-rule/note ?sort-note]]
                                                 "amount-lte" ['[?e :transaction-rule/amount-lte ?sort-amount-lte]]
                                                 "amount-gte" ['[?e :transaction-rule/amount-gte ?sort-amount-gte]]}
                                                  args)

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

                (:vendor-id args)
                (merge-query {:query {:in ['?vendor-id]
                                      :where ['[?e :transaction-rule/vendor ?vendor-id]]}
                              :args [(:vendor-id args)]})

                (not (str/blank? (:note args)))
                (merge-query {:query {:in ['?note-pattern]
                                      :where ['[?e :transaction-rule/note ?n]
                                              '[(re-find ?note-pattern ?n)]]}
                              :args [(re-pattern (str "(?i)" (:note args)))]})

                (not (str/blank? (:description args)))
                (merge-query {:query {:in ['?description]
                                      :where ['[?e :transaction-rule/description ?d]
                                              '[(clojure.string/lower-case ?d) ?d2]
                                              '[(clojure.string/includes? ?d2 ?description)]]}
                              :args [(clojure.string/lower-case (:description args))]})

                true
                (merge-query {:query {:find ['?e]
                                      :where ['[?e :transaction-rule/transaction-approval-status]]}}))]

    
    (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))
        transaction-rules (->> ids
                               (map results)
                               (map first)
                               (mapv <-datomic))]
    transaction-rules))

(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-by-id [id]
  (->> 
   (dc/pull (dc/db conn) default-read id)
   (<-datomic)))

(defn get-all []
  (mapv first
        (dc/q {:find  [(list 'pull '?e default-read )]
               :in    ['$]
               :where ['[?e :transaction-rule/transaction-approval-status]]}
              (dc/db conn))))

(defn get-all-for-client [client-id]
  (mapv first
        (dc/q '[:find  (pull ?e read)
                :in    $ ?c read
                :where
                [?e :transaction-rule/transaction-approval-status]
                (or-join [?e ?c]
                         [?e :transaction-rule/client ?c]
                         (and [?c :client/groups ?g]
                              [?e :transaction-rule/client-group ?g])
                         (and (not [?e :transaction-rule/client])
                              (not [?e :transaction-rule/client-group])))]
              (dc/db conn)
              client-id
              default-read)))