(ns auto-ap.plaid.core
  (:require [auto-ap.logging :as alog]
            [auto-ap.time :as atime]
            [cemerick.url :as url]
            [clj-http.client :as client]
            [clojure.data.json :as json]
            [config.core :as cfg :refer [env]]
            [slingshot.slingshot :refer [try+]]))

(def base-url (-> env :plaid :base-url))

(def client-id (-> env :plaid :client-id))
(def secret-key (-> env :plaid :secret-key))

(defn get-link-token [client-code]
  (-> (client/post (str base-url "/link/token/create") 
                   {:as :json
                    :headers {"Content-Type" "application/json"}
                    :body (json/write-str {"client_id" client-id
                                           "secret" secret-key
                                           "client_name" "Integreat Consulting"
                                           "country_codes" ["US"]
                                           "language" "en"
                                           "user" {"client_user_id" client-code}
                                           "products" ["transactions"]})})
      :body
      :link_token))

(defn get-relink-token [client-code access-token]
  (-> (client/post (str base-url "/link/token/create")
                   {:as :json
                    :headers {"Content-Type" "application/json"}
                    :body (json/write-str {"client_id" client-id
                                           "secret" secret-key
                                           "client_name" "Integreat Consulting"
                                           "access_token" access-token
                                           "country_codes" ["US"]
                                           "language" "en"
                                           "user" {"client_user_id" client-code}})})
      :body
      :link_token))



(defn exchange-public-token [public-token _]
  (-> (client/post (str base-url "/item/public_token/exchange") 
                   {:as :json
                    :headers {"Content-Type" "application/json"}
                    :body (json/write-str {"client_id" client-id
                                           "secret" secret-key
                                           "public_token" public-token})})
      :body))

(defn get-item [access-token]
  (try+
   (-> (client/post (str base-url "/item/get")
                    {:as :json
                     :headers {"Content-Type" "application/json"}
                     :body (json/write-str {"client_id" client-id
                                            "secret" secret-key
                                            "access_token" access-token})})
       :body)
   (catch [:status 400] x
     (let [json (try (json/read-str (:body x)) (catch Exception _
                                                 {}))]
       (throw (ex-info
               (or (get json "error_message")
                   (get json "display_message")
                   (.getMessage (:throwable &throw-context)))
               json))))))

(defn get-accounts [access-token]
  (try+
   (-> (client/post (str base-url "/accounts/get")
                    {:as :json
                     :headers {"Content-Type" "application/json"}
                     :body (json/write-str {"client_id" client-id
                                            "secret" secret-key
                                            "access_token" access-token})})
       :body)
   (catch [:status 400] x
     (let [json (try (json/read-str (:body x)) (catch Exception _
                                                 {}))]
       (throw (ex-info
               (or (get json "error_message")
                   (get json "display_message")
                   (.getMessage (:throwable &throw-context)))
               json))))))



(defn get-balance [access-token ]
  (-> (client/post (str base-url "/accounts/balance/get") 
                   {:as :json
                    :headers {"Content-Type" "application/json"}
                    :body (json/write-str {"access_token" access-token
                                           "secret" secret-key
                                           "client_id" client-id})})
      :body))

(defn get-transactions [access-token account-id start end]
  (alog/info  ::searching
              :start (str start)
              :end (str end)
              :acct (str account-id))


  (try+
   (-> (client/post (str base-url "/transactions/get")
                    {:as :json
                     :headers {"Content-Type" "application/json"}
                     :body (json/write-str {"client_id" client-id
                                            "secret" secret-key
                                            "access_token" access-token
                                            "start_date" (atime/unparse start atime/iso-date)
                                            "end_date" (atime/unparse end atime/iso-date)
                                            "options" {"account_ids" [account-id]
                                                       "count" 500}})})
       :body)
   (catch [:status 400] x
     (let [json (try (json/read-str (:body x)) (catch Exception _
                                                 {}))]
       (throw (ex-info
               (or (get json "error_message")
                   (get json "display_message")
                   (.getMessage (:throwable &throw-context)))
               json))))))

(comment
  (require '[datomic.api :as dc])

  (require '[auto-ap.datomic :refer [conn]])

  (doto (dc/q '[:find (pull ?ba [{:bank-account/plaid-account [* {:plaid-item/_accounts [*]}]}])
                :in $ ?ba]
              (dc/db conn)
              [:bank-account/code "NGHW-CB5029"])
    clojure.pprint/pprint)
  (require 'auto-ap.time-reader)

  (clojure.pprint/pprint
   (get-transactions "access-production-c0e322fa-f33d-4806-bc42-5fc883fb1ba4" "VZ8Y1azZMdhoYo9MQABrfpgz4jm4kPtakyxN5" #clj-time/date-time "2024-03-15" #clj-time/date-time "2024-03-30"))
  (clojure.pprint/pprint (get-accounts "access-production-c0e322fa-f33d-4806-bc42-5fc883fb1ba4"))

  )