(ns auto-ap.events
  (:require [re-frame.core :as re-frame]
            [auto-ap.db :as db]
            [auto-ap.subs :as subs]
            [auto-ap.routes :as routes]
            [auto-ap.effects :as effects]
            [auto-ap.utils :refer [by]]
            [venia.core :as v]
            [bidi.bidi :as bidi]
            [goog.crypt.base64 :as b64]
            [clojure.string :as str]))

(defn jwt->data [token]
  (js->clj (.parse js/JSON (b64/decodeString (second (str/split token #"\." ))))))

(re-frame/reg-event-fx
 ::initialize-db
 (fn  [{:keys [db]} [_ token]]
   (let [handler (:handler (bidi/match-route routes/routes (.. js/window -location -pathname)))]
     (cond
       (and (not= :login handler) (not token))
       {:redirect "/login"
        :db (assoc db/default-db
                   :active-page :login
                   :user token)}

       (and token (= "none" (get (jwt->data token) "role") ))
       {:redirect "/needs-activation"
        :db (assoc db/default-db
                   :active-page :needs-activation
                   :user token)}

       :else
       {:db (assoc db/default-db
                   :active-page handler
                   :user token)
        :graphql {:token token
                  :query-obj {:venia/queries [[:company
                                               [:id :name [:bank-accounts [:id :number :check-number :name]]]]
                                              [:vendor
                                               [:id :name]]]}
                  
                  :on-success [::received-initial]}}))))

(re-frame/reg-event-db
 ::toggle-menu
 (fn  [db [_ which]]
   (update-in db [:menu which :active?] #(not %))))

(re-frame/reg-event-fx
 ::logged-in
 (fn  [{:keys [db]} [_ token user]]
   {:graphql {:token token
              :query-obj {:venia/queries [[:company
                                               [:id :name [:bank-accounts [:id :number :check-number :name]]]]
                                              [:vendor
                                               [:id :name]]]}
              
              :on-success [::received-initial]}
    :db (assoc db :user (assoc user :token token))}))

(re-frame/reg-event-db
 ::received-initial
 (fn  [db [_ {companies :company vendors :vendor :as x}]]
   (-> db 
       (assoc :companies (by :id companies) )
       (assoc :vendors (by :id vendors) ))))

(re-frame/reg-event-db
 ::swap-company
 (fn  [db [_ company]]
   (assoc db :company (:id company))))

(re-frame/reg-event-db
 ::change-form
 (fn  [db [_ location field value]]
   (assoc-in db (into location field) value)))

(re-frame/reg-event-db
 ::modal-status
 (fn  [db [_ id  state]]
   (println "changing modal status" id "to")
   (update-in db [:modal-state id] #(merge % state))))

(re-frame/reg-event-db
 ::modal-completed
 (fn  [db [_ id  state]]
   (update-in db [:modal-state] #(dissoc % id))))

(re-frame/reg-event-fx
 ::set-active-page
 (fn  [{:keys [db]} [_ handler]]
   (if (and (not= :login handler) (not (:user db)))
     {:redirect "/login"
      :db (assoc db :active-page :login)}
     {:db (assoc db :active-page handler)})))

(re-frame/reg-event-db
 ::imported-invoices
 (fn  [db [_ new-invoices]]
   (assoc-in db [:invoices :pending] new-invoices)))

(re-frame/reg-event-fx
 ::approve-invoices
 (fn  [cofx [_]]
   {:http {:method :post
           :token (-> cofx :db :user)
           :uri (str "/api/invoices/approve"
                     (when-let [company-id (:id @(re-frame/subscribe [::subs/company]))]
                       (str "?company=" company-id)))
           :on-success [::received-invoices :pending]
           }}))

(re-frame/reg-event-fx
 ::view-pending-invoices
 (fn [cofx []]
   {:db (assoc-in (:db cofx) [:status :loading] true)
    :graphql {:token (-> cofx :db :user)
              :query-obj {:venia/queries [[:invoice
                                           {:imported false :company_id (:id @(re-frame/subscribe [::subs/company]))}
                                           [:id :total :invoice-number :date [:vendor [:name :id]] [:company [:name :id]]]]]}
              
              :on-success [::received-invoices :pending]}}))

(re-frame/reg-event-fx
 ::view-unpaid-invoices
 (fn [cofx []]
   {:db (assoc-in (:db cofx) [:status :loading] true)
    :graphql {:token (-> cofx :db :user)
              :query-obj {:venia/queries [[:invoice
                                           {:imported true :company_id (:id @(re-frame/subscribe [::subs/company]))}
                                           [:id :total :invoice-number :date [:vendor [:name :id]] [:company [:name :id]]]]]} 
              :on-success [::received-invoices :unpaid]}}))

(re-frame/reg-event-fx
 ::reject-invoices
 (fn  [cofx [_]]
   {:http {:method :post
           :token (-> cofx :db :user)
           :uri (str "/api/invoices/reject"
                     (when-let [company-id (:id @(re-frame/subscribe [::subs/company]))]
                       (str "?company=" company-id)))
           :on-success [::received-invoices :pending]
           }}))
(re-frame/reg-event-db
 ::submitted-new-invoice
 (fn  [db [_ invoice]]
   (assoc db :new-invoice {})))

(re-frame/reg-event-fx
 ::logout
 (fn  [{:keys [db]} [_]]
   {:db (assoc db :user nil :menu {:company {:active? false}
                                   :account {:active? false}})
    :redirect (bidi/path-for routes/routes :login)
    :set-local-storage ["jwt" nil]}))

(re-frame/reg-event-fx
 ::submit-new-invoice
 (fn  [{:keys [db]} [_ invoice]]
   {:http {:method :post
           :token (-> db :user)
           :uri "/api/invoices"
           :body (pr-str {:rows [(assoc invoice :imported true)]})
           :headers {"Content-Type" "application/edn"}
           :on-success [::submitted-new-invoice]}
    :db (assoc-in db [:new-invoice :loading?] true)}))

(re-frame/reg-event-db
 ::received-invoices
 (fn  [db [_ type result]]
   (let [new-invoices (if (:invoice result)
                        (:invoice result)
                        result)]
     (-> db
         (assoc-in [:invoices type]  new-invoices)
         (assoc-in [:status :loading] false)))))

(re-frame/reg-event-db
 ::change-form-state
 (fn  [db [_ target value]]
   (assoc-in db target value)))
