(ns auto-ap.routes.invoices
  (:require [auto-ap.datomic :refer [remove-nils uri]]
            [auto-ap.datomic.accounts :as d-accounts]
            [auto-ap.datomic.clients :as d-clients]
            [auto-ap.datomic.invoices :as d-invoices]
            [auto-ap.datomic.vendors :as d-vendors]
            [auto-ap.graphql.utils :refer [assert-admin assert-can-see-client]]
            [auto-ap.logging :refer [info-event]]
            [auto-ap.parse :as parse]
            [auto-ap.parse.util :as parse-u]
            [auto-ap.routes.utils :refer [wrap-secure]]
            [auto-ap.time-utils :refer [next-dom]]
            [auto-ap.utils :refer [by]]
            [auto-ap.yodlee.import :refer [grouped-import] :as y]
            [clj-time.coerce :as coerce :refer [to-date]]
            [clj-time.core :as time]
            [clojure.data.csv :as csv]
            [clojure.java.io :as io]
            [clojure.string :as str]
            [clojure.tools.logging :as log]
            [compojure.core :refer [context defroutes POST wrap-routes]]
            [datomic.api :as d]
            [ring.middleware.json :refer [wrap-json-response]]
            [unilog.context :as lc]))

(defn reset-id [i]
  (update i :invoice-number
          (fn [n] (if (re-matches #"#+" n)
                   nil
                   n))))

(defn assoc-client-code [i]
  (let [[client-code default-location] (str/split (:location i) #"-" )]
    (cond-> i
      client-code (assoc :client-code client-code)
      default-location (assoc :default-location default-location)
      (not client-code) (update :errors conj {:info "No client code found"})
      (not default-location) (update :errors conj {:info "No default location found"}))))

(defn parse-client [{:keys [client-code client default-location]} clients]
  (if-let [id (:db/id (or (clients client-code)
                       (clients client)))]
    (do
      (when (not ((set (:client/locations (or (clients client-code)
                                              (clients client))))
                  default-location))
        (throw (Exception. (str "Location '" default-location "' not found for client '" client-code "'.")))
        )
      id)
    (throw (Exception. (str "Client code '" client-code "' and client named '" client "' not found.")))))

(defn parse-invoice-number [{:keys [invoice-number]}]
  (or invoice-number ""))

(defn parse-vendor [{:keys [vendor-name check]} vendors]
  (let [v (vendors vendor-name)]
    (cond v
          v

          (= "Cash" check)
          nil

          :else
          (throw (Exception. (str "Vendor '" vendor-name "' not found."))))))

(defn parse-vendor-id [{:keys [vendor]}]
  (:db/id vendor))

(defn parse-automatically-paid-when-due [{:keys [vendor client-id]}]
  (boolean ((set (map :db/id (:vendor/automatically-paid-when-due vendor))) client-id)))

(defn parse-schedule-payment-dom [{:keys [vendor client-id]}]
  (get (by (comp :db/id :vendor-schedule-payment-dom/client) :vendor-schedule-payment-dom/dom (:vendor/schedule-payment-dom vendor))
       client-id))

(defn parse-amount [i]
  (try
    (Double/parseDouble (str/replace (or  (second
                                           (re-matches #"[^0-9\.,\\-]*([0-9\.,\\-]+)[^0-9\.,]*" (:amount i)))
                                          "0")
                                     #"," ""))
    (catch Exception e
      (throw (Exception. (str "Could not parse total from value '" (:amount i) "'") e)))))

(defn parse-account-numeric-code [i]
  (try
    (when-let [account-numeric-code (:account-numeric-code i)]
      (:db/id (d-accounts/get-account-by-numeric-code-and-sets (Integer/parseInt account-numeric-code)
                                                               ["default"])))
    (catch Exception e
      (throw (Exception. (str "Could not parse expense account from value '" (:account-numeric-code i) "'") e)))))

(defn parse-account-id [i]
  (try
    (Long/parseLong (second
                       (re-matches #"[^0-9,\\-]*([0-9,\\-]+)[^0-9,]*" (:bank-account-id i))))
    (catch Exception e
      (throw (Exception. (str "Could not parse account from value '" (:bank-account-id i) "'") e)))))



(defn parse-date [{:keys [raw-date]}]
  (when-not
      (re-find #"\d{1,2}/\d{1,2}/\d{4}" raw-date)
    (throw (Exception. (str "Date " raw-date " must match MM/dd/yyyy"))))
  (try 

    (parse-u/parse-value :clj-time "MM/dd/yyyy" raw-date)
    (catch Exception e
      (throw (Exception. (str "Could not parse date from '" raw-date "'") e)))))

(defn parse-or-error [key f]
  (fn [x]
    (try
      (assoc x key (f x))
      (catch Exception e
        (update x :errors conj {:info (.getMessage e)
                                :details (str e)})))))

(defn parse-invoice-rows [excel-rows]
  (let [columns [:raw-date :vendor-name :check :location :invoice-number :amount :client-name :bill-entered :bill-rejected :added-on :exported-on :account-numeric-code]
        all-vendors (by :vendor/name (d-vendors/get-graphql {})) 
        all-clients (d-clients/get-all)
        all-clients (merge  (by :client/code all-clients) (by :client/name all-clients))
        rows (->> (str/split excel-rows #"\n" )
                  (map #(str/split % #"\t"))
                  (map #(into {} (map (fn [c k] [k c] ) % columns)))
                  (map reset-id)
                  (map assoc-client-code)
                  (map (parse-or-error :client-id #(parse-client % all-clients)))
                  (map (parse-or-error :vendor #(parse-vendor % all-vendors)))
                  (map (parse-or-error :vendor-id #(parse-vendor-id %)))
                  (map (parse-or-error :automatically-paid-when-due #(parse-automatically-paid-when-due %)))
                  (map (parse-or-error :schedule-payment-dom #(parse-schedule-payment-dom %)))
                  (map (parse-or-error :account-id parse-account-numeric-code))
                  (map (parse-or-error :invoice-number parse-invoice-number))
                  (map (parse-or-error :total parse-amount))
                  (map (parse-or-error :date parse-date)))]

    
    rows))

(defn invoice-rows->transaction [rows]
  (->> rows
       (mapcat (fn [{:keys [vendor-id total client-id amount date invoice-number default-location account-id check vendor automatically-paid-when-due schedule-payment-dom]}]
                 (let [invoice (cond->
                                   #:invoice {:db/id (.toString (java.util.UUID/randomUUID))
                                              :vendor vendor-id
                                              :client client-id
                                              :default-location default-location
                                              :import-status :import-status/imported
                                              :automatically-paid-when-due automatically-paid-when-due
                                              #_#_:default-expense-account default-expense-account
                                              :total total 
                                              :outstanding-balance (if (= "Cash" check)
                                                                     0.0
                                                                     total)
                                              :status (if (= "Cash" check)
                                                        :invoice-status/paid
                                                        :invoice-status/unpaid)
                                              :invoice-number invoice-number
                                              :date (to-date date)
                                              :expense-accounts [#:invoice-expense-account {:account (or account-id
                                                                                                         (:db/id (d-vendors/account-for-client-id vendor client-id)))
                                                                                            :location default-location
                                                                                            :amount total}]}
                                 (:vendor/terms vendor) (assoc :invoice/due (coerce/to-date
                                                                             (time/plus date (time/days (d-vendors/terms-for-client-id vendor client-id)))))
                                 automatically-paid-when-due (assoc :invoice/scheduled-payment (coerce/to-date
                                                                                                (time/plus date (time/days (d-vendors/terms-for-client-id vendor client-id)))))
                                 schedule-payment-dom (assoc :invoice/scheduled-payment (coerce/to-date
                                                                                         (next-dom date schedule-payment-dom)
                                                                                         )))
                       payment (if (= :invoice-status/paid (:invoice/status invoice)) 
                                 #:invoice-payment {:invoice (:db/id invoice)
                                                    :amount (:invoice/total invoice)
                                                    :payment (remove-nils #:payment {:db/id (.toString (java.util.UUID/randomUUID))
                                                                                     :vendor (:invoice/vendor invoice)
                                                                                     :client (:invoice/client invoice)
                                                                                     :type :payment-type/cash
                                                                                     :amount (:invoice/total invoice)
                                                                                     :status :payment-status/cleared 
                                                                                     :date (:invoice/date invoice)})}
                                 )]
                   [[:propose-invoice (remove-nils invoice)]
                    (some-> payment remove-nils)])))
       (filter identity)))


(defn match-vendor [vendor-code forced-vendor]
  (when (and (not forced-vendor) (str/blank? vendor-code))
    (throw (ex-info (str "No vendor found. Please supply an forced vendor.")
                    {:vendor-code vendor-code})))
  (let [vendor-id (or forced-vendor
                      (->> (d/query
                            {:query {:find ['?vendor]
                                     :in ['$ '?vendor-name]
                                     :where ['[?vendor :vendor/name ?vendor-name]]}
                             :args [(d/db (d/connect uri)) vendor-code]})
                           first
                           first))]
    (when-not vendor-id
      (throw (ex-info (str "Vendor matching name \"" vendor-code "\" not found.")
                      {:vendor-code vendor-code})))

    (if-let [matching-vendor (->> (d/query
                                   {:query {:find [(list 'pull '?vendor-id d-vendors/default-read)]
                                            :in ['$ '?vendor-id]}
                                    :args [(d/db (d/connect uri)) vendor-id]})
                                  first
                                  first)]
      matching-vendor
      (throw (ex-info (str "No vendor with the name " vendor-code " was found.")
                      {:vendor-code vendor-code})))))

(defn import-uploaded-invoice [user client forced-location forced-vendor imports]
  (lc/with-context {:area "upload-invoice"}
    (log/info "Number of invoices to import is" (count imports) "sample: " (first imports))
    (let [clients (d-clients/get-all)
          transactions (reduce (fn [result {:keys [invoice-number customer-identifier account-number total date vendor-code text full-text] :as info}]
                                 
                                 (let [ 
                                       matching-client (or (and account-number
                                                                (parse/best-match clients account-number 0.0))
                                                           (and customer-identifier
                                                                (parse/best-match clients customer-identifier))
                                                           (if client
                                                             (first (filter (fn [c]
                                                                              (= (:db/id c) (Long/parseLong client)))
                                                                            clients))))
                                       _ (assert-can-see-client user (:db/id matching-client))
                                       _ (when-not matching-client
                                           (throw (ex-info (str "Searched clients for '" customer-identifier "'. No client found in file. Select a client first.")
                                                           {:invoice-number invoice-number
                                                            :customer-identifier customer-identifier
                                                            :vendor-code vendor-code})))

                                       matching-vendor (match-vendor vendor-code forced-vendor)

                                       
                                       _ (info-event "Found match for invoice" {:invoice-number invoice-number
                                                                                :vendor (select-keys matching-vendor [:vendor/name :db/id])
                                                                                :client (select-keys matching-client [:client/name :db/id])})
                                       matching-location (or (when-not (str/blank? forced-location)
                                                               forced-location)
                                                             (parse/best-location-match matching-client text full-text))
                                       [existing-id existing-outstanding-balance existing-status import-status] (when (and matching-client matching-location)
                                                                                                                  (try
                                                                                                                    (->> (d/query
                                                                                                                          (cond-> {:query {:find ['?e '?outstanding-balance '?status '?import-status2]
                                                                                                                                           :in ['$ '?invoice-number '?vendor '?client]
                                                                                                                                           :where '[[?e :invoice/invoice-number ?invoice-number]
                                                                                                                                                    [?e :invoice/vendor ?vendor]
                                                                                                                                                    [?e :invoice/client ?client]
                                                                                                                                                    [?e :invoice/outstanding-balance ?outstanding-balance]
                                                                                                                                                    [?e :invoice/status ?status]
                                                                                                                                                    [?e :invoice/import-status ?import-status]
                                                                                                                                                    [?import-status :db/ident ?import-status2]]}
                                                                                                                                   :args [(d/db (d/connect uri)) invoice-number (:db/id matching-vendor) (:db/id matching-client)]}))
                                                                                                                         first)
                                                                                                                    (catch Exception e
                                                                                                                      (throw (ex-info (str "Failed to find potential matching invoice with"
                                                                                                                                           " invoice " invoice-number
                                                                                                                                           " vendor " matching-vendor
                                                                                                                                           " client " (:client/name matching-client)
                                                                                                                                           ". "
                                                                                                                                           (.toString e))
                                                                                                                                      {:args [ invoice-number matching-vendor (:db/id matching-client)]})))
                                                                                                                    ))
                                       automatically-paid-for (set (map :db/id (:vendor/automatically-paid-when-due matching-vendor)))
                                       schedule-payment-dom (get (by (comp :db/id :vendor-schedule-payment-dom/client) :vendor-schedule-payment-dom/dom (:vendor/schedule-payment-dom matching-vendor))
                                                                 (:db/id matching-client))]
                                   
                                   (cond
                                     (not (and matching-location matching-client))
                                     result

                                     (= :import-status/imported import-status)
                                     result

                                     :else
                                     (conj result [:propose-invoice (cond-> (remove-nils #:invoice {:invoice/client (:db/id matching-client)
                                                                                                    :invoice/client-identifier customer-identifier
                                                                                                    :invoice/vendor (:db/id matching-vendor)
                                                                                                    :invoice/invoice-number invoice-number
                                                                                                    :invoice/total (Double/parseDouble total)
                                                                                                    :invoice/date (to-date date)
                                                                                                    :invoice/import-status :import-status/pending
                                                                                                    :invoice/outstanding-balance (or existing-outstanding-balance (Double/parseDouble total))
                                                                                                    :invoice/status (or existing-status :invoice-status/unpaid)
                                                                                                    :invoice/expense-accounts (when-not existing-id [#:invoice-expense-account {:account (d-vendors/account-for-client-id matching-vendor (:db/id matching-client))
                                                                                                                                                                                :location matching-location
                                                                                                                                                                                :amount (Double/parseDouble total)}])
                                                                                                    :db/id existing-id
                                                                                                    })
                                                                      (:vendor/terms matching-vendor) (assoc :invoice/due (coerce/to-date
                                                                                                                           (time/plus date (time/days (d-vendors/terms-for-client-id matching-vendor (:db/id matching-client))))))
                                                                      (boolean (automatically-paid-for (:db/id matching-client))) (assoc :invoice/scheduled-payment (coerce/to-date
                                                                                                                                                                     (time/plus date (time/days (d-vendors/terms-for-client-id matching-vendor (:db/id matching-client))))))
                                                                      schedule-payment-dom (assoc :invoice/scheduled-payment (to-date
                                                                                                                              (next-dom date schedule-payment-dom))))]))
                                   ))
                               []
                               imports)]
      (when-not (seq transactions)
        (throw (ex-info "No new invoices found."
                        {:imports (str imports)})))
      (log/info "creating invoice" transactions)
      @(d/transact (d/connect uri) (vec (set transactions))))))


(defn validate-account-rows [rows code->existing-account]
  (when-let [bad-types (seq (->> rows
                                 (filter (fn [[account _ _ type :as row]]
                                           (and (not (code->existing-account (Integer/parseInt account)))
                                                (not (#{"Asset" "Liability" "Revenue" "Expense" "Equity" "Dividend"} type)))
                                           ))))]
    (throw (ex-info (str "You are adding accounts without a valid type" )
                    {:rows bad-types})))

  (when-let [duplicate-rows (seq (->> rows
                                      (filter (fn [[account]]
                                                (not-empty account)))
                                      (group-by (fn [[account]]
                                                  account))
                                      vals
                                      (filter #(> (count %) 1))
                                      (filter (fn [duplicates]
                                                (apply not= duplicates)))
                                      #_(map (fn [[[_ account]]]
                                               account))
                                      ))]
    (throw (ex-info (str "You have duplicated rows with different values." )
                    {:rows duplicate-rows}))))

(defn import-account-overrides [customer filename]
  (let [conn (d/connect uri)
        [header & rows] (-> filename (io/reader) csv/read-csv)
        [client-id] (first (d/query (-> {:query {:find ['?e]
                                                 :in ['$ '?z]
                                                 :where [['?e :client/code '?z]]}
                                         :args [(d/db (d/connect uri)) customer]})))
        headers (map read-string header)
        code->existing-account (by :account/numeric-code (map first (d/query {:query {:find ['(pull ?e [:account/numeric-code
                                                                                                        {:account/applicability [:db/ident]}
                                                                                                        :db/id])]
                                                                                      :in ['$]
                                                                                      :where ['[?e :account/name]]}
                                                                              :args [(d/db conn)]})))  

        existing-account-overrides (d/query (-> {:query {:find ['?e]
                                                         :in ['$ '?client-id]
                                                         :where [['?e :account-client-override/client '?client-id]]}
                                                 :args [(d/db (d/connect uri)) client-id]}))

        
        rows (transduce (comp
                         (map (fn [[_ account account-name override-name _ type]]
                                [account account-name override-name type]))
                         (filter (fn [[account]]
                                   (not-empty account))))
                        conj
                        []
                        rows)
        
        _ (validate-account-rows rows code->existing-account)
        rows (vec (set rows))

        txes (transduce
              (comp
               (mapcat (fn parse-map [[account account-name override-name type]]
                         (let [code (some-> account
                                            not-empty
                                            Integer/parseInt)
                               existing (code->existing-account code)]
                           (cond (not code)
                                 []

                                 (and existing (or (#{:account-applicability/optional :account-applicability/customized}
                                                    (:db/ident (:account/applicability existing)))
                                                   (and (not-empty override-name)
                                                        (not-empty account-name)
                                                        (not= override-name account-name)
                                                        )))
                                 [{:db/id (:db/id existing)
                                   :account/client-overrides [{:account-client-override/client client-id
                                                               :account-client-override/name (or (not-empty override-name)
                                                                                                 (not-empty account-name))}]}]

                                 (not existing)
                                 [{:account/applicability :account-applicability/customized
                                   :account/name account-name
                                   :account/account-set "default"
                                   :account/numeric-code code
                                   :account/code (str code)
                                   :account/type (if (str/blank? type)
                                                   :account-type/expense
                                                   (keyword "account-type" (str/lower-case type)))
                                   :account/client-overrides [{:account-client-override/client client-id
                                                               :account-client-override/name (or (not-empty override-name)
                                                                                                 (not-empty account-name))}]}]
                                 :else
                                 [])))))

              conj
              (mapv
               (fn [[x]]
                 [:db/retractEntity x])
               existing-account-overrides)
              rows)]
   
    @(d/transact conn txes)
    txes))
    
   

(defn import-transactions-cleared-against [file]
  (let [[header & rows] (-> file (io/reader) csv/read-csv)
        txes (transduce
              (comp 
               (filter (fn [[transaction-id cleared-against]]
                         (d/pull (d/db (d/connect uri)) '[:transaction/amount] (Long/parseLong transaction-id))))
               (map (fn [[transaction-id cleared-against]]
                      {:db/id (Long/parseLong transaction-id)
                       :transaction/cleared-against cleared-against})))
              conj
              []
              rows)]
    @(d/transact (d/connect uri) txes)))

(defroutes routes
  (wrap-routes
   (context "/" []
            (context "/transactions" []
                     (POST "/batch-upload"
                           {{:keys [data]}  :edn-params user :identity}
                           (assert-admin user)

                           (try
                             #_(throw (Exception. "Unexpected error"))
                             (let [columns [:status :raw-date :description-original :high-level-category nil nil :amount nil nil nil nil nil :bank-account-code :client-code]
                                   all-clients (d-clients/get-all)
                                   all-bank-accounts (mapcat :client/bank-accounts all-clients)
                                   all-clients (merge  (by :client/code all-clients) (by :client/name all-clients))
                                   all-bank-accounts (merge  (by :bank-account/code all-bank-accounts))
                                   rows (->> (str/split data #"\n" )
                                             (drop 1)
                                             (map #(str/split % #"\t"))
                                             (map #(into {} (filter identity (map (fn [c k] [k c] ) % columns))))
                                             (map (parse-or-error :amount parse-amount))
                                             (map (parse-or-error :date parse-date))
                                             (map (fn [{:keys [bank-account-code] :as row}]
                                                    (if-let [bank-account-id (:db/id (all-bank-accounts bank-account-code))]
                                                      (assoc row :bank-account-id bank-account-id)
                                                      (update row :errors conj {:info (str "Cannot find bank by code " bank-account-code)
                                                                                :details (str "Cannot find bank by code " bank-account-code)}))))
                                             (map (fn [{:keys [client-code] :as row}]
                                                    (if-let [client-id (:db/id (all-clients client-code))]
                                                      (assoc row :client-id client-id)
                                                      (update row :errors conj {:info (str "Cannot find client by code " client-code)
                                                                                :details (str "Cannot find client by code " client-code)})))))
                                   error-rows (filter :errors rows)
                                   _ (log/info "Importing " (count rows) "raw transactions")
                                   raw-transactions (vec (->> rows
                                                              (filter #(not (seq (:errors %))) )
                                                              (map (fn [row]
                                                                     (select-keys row [:description-original :client-code :status :high-level-category :amount :bank-account-id :date :client-id])))))
                                   import-id (y/start-import :import-source/manual (:user/name user))
                                   result (grouped-import raw-transactions import-id)]
                               (y/finish-import {:db/id import-id
                                                 :import-batch/imported (count (:import result))
                                                 :import-batch/suppressed (count (:suppressed result))
                                                 :import-batch/extant (count (:extant result))})
                             
                             {:status 200
                              :body (pr-str {:imported (count (:import result))
                                             :errors (map #(dissoc % :date) error-rows)})
                              :headers {"Content-Type" "application/edn"}})
                             (catch Exception e
                               (log/error e)
                               {:status 500
                                :body (pr-str {:message (.getMessage e)
                                               :error (.toString e)
                                               :data (ex-data e)})
                                :headers {"Content-Type" "application/edn"}}))
                           ))

            (context "/invoices" []
                     (POST "/upload"
                           {{files :file
                             files-2 "file"
                             client :client
                             client-2 "client"
                             location :location
                             location-2 "location"
                             vendor :vendor
                             vendor-2 "vendor"} :params :as params
                            user :identity}
                           (let [files (or files files-2)
                                 client (or client client-2)
                                 location (or location location-2)
                                 vendor (some-> (or vendor vendor-2)
                                                (Long/parseLong))
                                 {:keys [filename tempfile]} files]
                             (lc/with-context {:parsing-file filename}
                               (try
                                 (import-uploaded-invoice user client location vendor (parse/parse-file (.getPath tempfile) filename))
                                 {:status 200
                                  :body (pr-str {})
                                  :headers {"Content-Type" "application/edn"}}
                                 (catch Exception e
                                   (log/warn e)
                                   {:status 500
                                    :body (pr-str {:message (.getMessage e)
                                                   :error (.toString e)
                                                   :data (ex-data e)})
                                    :headers {"Content-Type" "application/edn"}})))))
                     
                     (POST "/upload-integreat"
                           {{:keys [excel-rows]}  :edn-params user :identity}
                           (assert-admin user)
                           (let [parsed-invoice-rows (parse-invoice-rows excel-rows)
                                 existing-rows (set (d-invoices/get-existing-set ))
                                 grouped-rows (group-by
                                               (fn [i]
                                                 (cond (seq (:errors i))
                                                       :error

                                                       (existing-rows [(:vendor-id i) (:client-id i) (:invoice-number i)])
                                                       :exists

                                                       :else
                                                       :new))
                                               parsed-invoice-rows)
                                 vendors-not-found (->> parsed-invoice-rows
                                                        (filter #(and (nil? (:vendor-id %))
                                                                      (not= "Cash" (:check %))))
                                                        (map :vendor-name)
                                                        set)
                                 inserted-rows @(d/transact (d/connect uri) (invoice-rows->transaction (:new grouped-rows)))]
                             {:status 200
                              :body (pr-str {:imported (count (:new grouped-rows))
                                             :already-imported (count (:exists grouped-rows))
                                             :vendors-not-found vendors-not-found
                                             :errors (map #(dissoc % :date) (:error grouped-rows))})
                              :headers {"Content-Type" "application/edn"}})))
            (POST "/transactions/cleared-against"
                           {{files :file
                             files-2 "file"} :params :as params
                            user :identity}
                           (let [files (or files files-2)
                                 {:keys [filename tempfile]} files]
                             (assert-admin user)
                             (try
                               (import-transactions-cleared-against (.getPath tempfile))
                               {:status 200
                                :body (pr-str {})
                                :headers {"Content-Type" "application/edn"}}
                               (catch Exception e
                                 (log/error e)
                                 {:status 500
                                  :body (pr-str {:message (.getMessage e)
                                                 :error (.toString e)
                                                 :data (ex-data e)})
                                  :headers {"Content-Type" "application/edn"}}))))
            (wrap-json-response (POST "/account-overrides"
                                      {{files :file
                                        files-2 "file"
                                        client :client
                                        client-2 "client"} :params :as params
                                       user :identity}
                                      (let [files (or files files-2)
                                            client (or client client-2)
                                            {:keys [filename tempfile]} files]
                                        (assert-admin user)
                                        (try
                                          {:status 200
                                           :body (import-account-overrides client (.getPath tempfile))
                                           :headers {"Content-Type" "application/json"}}
                                          (catch Exception e
                                            (log/error e)
                                            {:status 500
                                             :body {:message (.getMessage e)
                                                    :data (ex-data e)}
                                             :headers {"Content-Type" "application/json"}}))))))
   wrap-secure))
