(ns auto-ap.intuit.core
  (:require [amazonica.aws.s3 :as s3]
            [clj-http.client :as client]
            [clj-time.coerce :as c]
            [clojure.core.memoize :as m]
            [clojure.java.io :as io]
            [clojure.string :as str]
            [config.core :as cfg :refer [env]])
  (:import (org.apache.commons.codec.binary Base64)))

;; (def authorization-code "AB11638463964I0tYPR3A1inog2HL407u2bZBXHg6LEqCbILRO")
;; (def realm-id "4620816365202617680")

;; (def company-id "4620816365202617680")

;; (def base-url "https://sandbox-quickbooks.api.intuit.com/v3")


(def prod-client-id "ABFRwAiOqQiLN66HKplXfyRE3ipD390DHsrUquflRCiOa81mxa")
(def prod-client-secret "xDUj04GeQXpLvrhxep1jjDYwjJWbzzOPrirUQTKF")

;; (def prod-redirect-uri "https://developer.intuit.com/v2/OAuth2Playground/RedirectUrl")
;; (def prod-authorization-code "AB11638464998wYuapsEGtIEnRqphrw0H97XUnvEG2dK4cGUyL")
;; (def prod-realm-id "123146163906404")

;;  "refreshToken": "AB11647191065B0olWYQ61wfq8uszBusfe6Jpn7Au7qY5exkLL",
;; "accessToken":,
;;



(def prod-company-id "123146163906404")


(def prod-base-url "https://quickbooks.api.intuit.com/v3")

(defn set-access-token [t]
  (s3/put-object :bucket-name (:data-bucket env) 
                 :key (str "intuit/access-token")
                 :input-stream (io/make-input-stream (.getBytes t) {})
                 :metadata {:content-type "application/text"
                            :content-length (count (.getBytes t))}))
(defn set-refresh-token [t]
  (s3/put-object :bucket-name (:data-bucket env) 
                 :key (str "intuit/refresh-token")
                 :input-stream (io/make-input-stream (.getBytes t) {})
                 :metadata {:content-type "application/text"
                            :content-length (count (.getBytes t))}))

#_{:clj-kondo/ignore [:clojure-lsp/unused-public-var]}
(defn copy-prod-refresh-token []
  (set-refresh-token (slurp  (:object-content (s3/get-object
                                               :bucket-name "data.prod.app.integreatconsult.com"
                                               :key "intuit/refresh-token")))))


#_{:clj-kondo/ignore [:clojure-lsp/unused-public-var]}
(defn init-tokens [access refresh]
  (set-access-token access)
  (set-refresh-token refresh))

#_{:clj-kondo/ignore [:clojure-lsp/unused-public-var]}
(defn lookup-access-token []
  (slurp  (:object-content (s3/get-object
                            :bucket-name (:data-bucket env)
                            :key "intuit/access-token"))))

#_{:clj-kondo/ignore [:clojure-lsp/unused-public-var]}
(defn lookup-refresh-token []
  (slurp  (:object-content (s3/get-object
                            :bucket-name (:data-bucket env)
                            :key "intuit/refresh-token"))))

(defn get-basic-auth []
  (Base64/encodeBase64String (.getBytes (str prod-client-id ":" prod-client-secret))))


(defn get-fresh-access-token []
  (let [refresh-token (lookup-refresh-token)
        response (:body (client/post  (str "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer" )

                             {:headers {"Accept" "application/json"
                                        "Content-Type" "application/x-www-form-urlencoded"
                                        "Authorization" (str "Basic " (get-basic-auth))}
                              :form-params {"grant_type" "refresh_token"
                                            "refresh_token" refresh-token}
                              :as :json}))]
    (set-access-token (:access_token response))
    (set-refresh-token (:refresh_token response))
    (:access_token response)))

(def prod-base-headers {"Accept" "application/json"
                        "Content-Type" "application/json"})
(defn with-auth [t token]
  (assoc t "Authorization" (str "Bearer " token)))

#_(client/get (str base-url "/company/4620816365202617680") 
            {:headers base-headers
             :as :json})

(defn get-bank-accounts-raw [token]
  (->> (:body (client/get (str prod-base-url "/company/" prod-company-id "/query" ) 
                          {:headers
                           (with-auth prod-base-headers token)
                           :as :json
                           :query-params {"query" "SELECT * From Account maxresults 1000"}}))
       :QueryResponse))


(defn get-bank-accounts [token]
  (->> (:body (client/get (str prod-base-url "/company/" prod-company-id "/query" ) 
                          {:headers
                           (with-auth prod-base-headers token)
                           :as :json
                           :query-params {"query" "SELECT * From Account maxresults 1000"}}))
       :QueryResponse
       :Account
       #_(filter
        #(#{"Bank" "Credit Card"} (:AccountType %)))
       (map (juxt :Id :Name :CurrentBalance :MetaData))
       (map (fn [[id name current-balance metadata]]
              {:id id
               :name name
               :last-updated (c/to-date-time (-> metadata :LastUpdatedTime))
               :current-balance (try (double current-balance) (catch Exception _ nil))}))))


(defn get-all-transactions [start end]
  (let [token (get-fresh-access-token)]
    (:body (client/get (str prod-base-url "/company/" prod-company-id "/reports/TransactionList" "?minorversion=63&start_date=" start "&end_date=" end) 
                       {:headers (with-auth prod-base-headers token)
                        :as      :json}))))

(def memoize-get-all-transactions (m/ttl get-all-transactions :ttl/threshold 60000))

(defn get-transactions [start end external-id]
  (let [body (memoize-get-all-transactions start end)
        headers (map :ColTitle (:Column (:Columns body)))
        rows (map :ColData (:Row (:Rows body)))]
    (->> rows
         (map
          (fn [row]
            (into {}
                  (map
                   (fn [h r]
                     [(keyword h) (:value r)])
                   headers
                   row))))
         (filter #(str/includes? (:Account %) external-id)))))


