(ns auto-ap.yodlee.import
  (:require [auto-ap.yodlee.core :as client]
            [auto-ap.utils :refer [by]]
            [datomic.api :as d]
            [auto-ap.datomic :refer [uri remove-nils]]
            [clj-time.coerce :as coerce]
            [digest :refer [sha-256]]
            [auto-ap.datomic.checks :as d-checks]
            [auto-ap.datomic.clients :as d-clients]
            [auto-ap.time :as time]))



(defn transaction->check-id [_ check-number client-id bank-account-id amount]
  (cond (and check-number client-id bank-account-id)
        (-> (d-checks/get-graphql {:client-id client-id
                                   :bank-account-id bank-account-id 
                                   :check-number check-number
                                   :amount (- amount)
                                   :status :payment-status/pending})
            first
            :db/id)

        (and client-id bank-account-id amount)
        
        (let [matching-checks (d-checks/get-graphql {:client-id client-id
                                                   :bank-account-id bank-account-id 
                                                   :amount (- amount)
                                                   :status :payment-status/pending})]
          (if (= 1 (count matching-checks))
            (:db/id (first matching-checks))
            nil))

        :else
        nil))

(defn extract-check-number [{{description-original :original} :description}]
  
  (if-let [[_ _ check-number] (re-find #"(?i)check(card|[^0-9]+([0-9]*))" description-original)]
    (try
      (Integer/parseInt check-number)
      (catch NumberFormatException e
        nil))
    nil))

(defn import-transactions [transactions transaction->client transaction->bank-account-id]
  (doseq [transaction transactions
          :let [{post-date :postDate
                 account-id :accountId
                 date :date
                 id :id
                 {amount :amount} :amount
                 {description-original :original
                  description-simple :simple} :description
                 {merchant-id :i
                  merchant-name :name} :merchant
                 base-type :baseType
                 type :type
                 status :status}
                transaction
                amount (if (= "DEBIT" base-type)
                         (-  amount)
                         amount)
                check-number (extract-check-number transaction)
                client-id (transaction->client transaction) 
                bank-account-id (transaction->bank-account-id transaction)
                check-id (transaction->check-id transaction check-number client-id bank-account-id amount)]]
    (try
      (when client-id
        @(->> [(remove-nils #:transaction
                            {:post-date (coerce/to-date (time/parse post-date "YYYY-MM-dd"))
                             :id (sha-256 (str id))
                             :account-id account-id
                             :date (coerce/to-date (time/parse date "YYYY-MM-dd"))
                             :amount (double amount)
                             :description-original description-original
                             :description-simple description-simple
                             :type type
                             :status status
                             :client client-id
                             :check-number check-number
                             :bank-account (transaction->bank-account-id transaction) 
                             :payment (when check-id
                                        {:db/id check-id
                                         :payment/status :payment-status/cleared}
                                        )
                             })]

             
             (d/transact (d/connect uri))))

      (catch Exception e
        (println e)))))

(defn manual-import [manual-transactions]
  (let [transformed-transactions (->> manual-transactions
                                      (filter #(= "posted" (:status %)))
                                      (group-by #(select-keys % [:date :description-original :amount]))
                                      (vals)
                                      (mapcat (fn [transaction-group]
                                                (map
                                                 (fn [index {:keys [date description-original high-level-category amount bank-account-id client-id] :as transaction}]
                                                   {:id (str date "-" bank-account-id "-" description-original "-" amount "-" index "-" client-id)
                                                    :client-id client-id
                                                    :bank-account-id bank-account-id
                                                    :date (time/unparse  date "YYYY-MM-dd")
                                                    :amount {:amount amount}
                                                    :description {:original description-original
                                                                  :simple high-level-category}
                                                    :status "POSTED"})
                                                 (range)
                                                 transaction-group))))]
    (println "importing manual transactions" transformed-transactions)
    (import-transactions transformed-transactions :client-id :bank-account-id)))

(defn do-import []
  (let [transactions (client/get-transactions)
        #_#__ (println "All accounts:" (client/get-accounts))
        #_#__ (println "ALL Transactions:" transactions)
        all-bank-accounts (mapcat (fn [c] (map
                                          (fn [{:keys [:db/id :bank-account/yodlee-account-id]}]
                                            (when (and id yodlee-account-id)
                                              {:bank-account-id id
                                               :client-id (:db/id c)
                                               :yodlee-account-id yodlee-account-id}))
                                          (:client/bank-accounts c)))
                                  (d-clients/get-all)) 
        transaction->client (comp (by :yodlee-account-id :client-id all-bank-accounts) :accountId)
        transaction->bank-account-id (comp (by :yodlee-account-id :bank-account-id all-bank-accounts) :accountId)]
    (import-transactions transactions transaction->client transaction->bank-account-id)))

