(ns auto-ap.import.intuit
  (:require [auto-ap.datomic :refer [conn]]
            [auto-ap.import.common :refer [wrap-integration]]
            [auto-ap.import.transactions :as t]
            [auto-ap.intuit.core :as i]
            [auto-ap.logging :as alog]
            [auto-ap.time :as atime]
            [clj-time.coerce :as coerce]
            [clj-time.core :as time]
            [clojure.string :as str]
            [com.unbounce.dogstatsd.core :as statsd]
            [datomic.api :as dc]
            [iol-ion.utils :refer [remove-nils]]))

(defn get-intuit-bank-accounts 
  ( [db]
                                (dc/q '[:find ?external-id ?ba ?c
                                        :in $ 
                                        :where
                                        [?c :client/bank-accounts ?ba]
                                        [?ba :bank-account/intuit-bank-account ?iab]
                                        [?iab :intuit-bank-account/external-id ?external-id]]
                                      db))
  ([db & client-codes]
   (dc/q '[:find ?external-id ?ba ?c
           :in $ [?cc ...]
           :where
           [?c :client/code ?cc]
           [?c :client/bank-accounts ?ba]
           [?ba :bank-account/intuit-bank-account ?iab]
           [?iab :intuit-bank-account/external-id ?external-id]]
         db
         client-codes)))


(defn intuit->transaction [transaction]
  (let [check-number (when (not (str/blank? (:Num transaction)))
                       (try
                         (Integer/parseInt (:Num transaction))
                         (catch NumberFormatException e
                           (alog/warn ::invalid-check-number :check-number (:Num transaction) :error e)
                           nil)))]
    (cond-> {:transaction/description-original (:Memo/Description transaction)
             :transaction/amount (Double/parseDouble (:Amount transaction))
             :transaction/date (coerce/to-date (atime/parse (:Date transaction) atime/iso-date))
             :transaction/status "POSTED"}
      check-number (assoc :transaction/check-number check-number))))


(defn intuits->transactions [transactions bank-account-id client-id]
  (->> transactions
       (map intuit->transaction)
       (map #(assoc %
                    :transaction/bank-account bank-account-id
                    :transaction/client client-id))
       (t/apply-synthetic-ids)))

(defn import-intuit []
  (statsd/event {:title    "Intuit import started"
                 :text     "Starting"
                 :priority :low}
                nil)
  (let [import-batch (t/start-import-batch :import-source/intuit "Automated intuit user")
        db           (dc/db conn)
        end          (auto-ap.time/local-now)
        start        (time/plus end (time/days -30))]
    (try
      (doseq [[external-id bank-account-id client-id] (get-intuit-bank-accounts db)
              transaction                             (wrap-integration #(-> (i/get-transactions (auto-ap.time/unparse start auto-ap.time/iso-date)
                                                                                                 (auto-ap.time/unparse end auto-ap.time/iso-date)
                                                                                                 external-id)
                                                                             (intuits->transactions bank-account-id client-id))
                                                                        bank-account-id)]
        (t/import-transaction! import-batch transaction))
      (t/finish! import-batch)
      (statsd/event {:title    "Intuit import Finished"
                     :text     (pr-str (t/get-stats import-batch))
                     :priority :low}
                    nil)
      (catch Exception e
        (t/fail! import-batch e)
        (statsd/event {:title      "Intuit import failed"
                       :text       (str e)
                       :alert-type :warning
                       :priority   :normal}
                      nil)))))

(defn upsert-accounts []
  (let [token (i/get-fresh-access-token)
        bank-accounts (i/get-bank-accounts token)]
    @(dc/transact conn (mapv
                        (fn [ba]
                          (remove-nils
                           {:intuit-bank-account/external-id (:name ba)
                            :intuit-bank-account/name        (:name ba)
                            :intuit-bank-account/last-synced (coerce/to-date (:last-updated ba))
                            :intuit-bank-account/current-balance (:current-balance ba)}))
                        bank-accounts))))
