(ns auto-ap.views.pages.import-invoices
  (:require [re-frame.core :as re-frame]
            [reagent.core :as reagent]
            [reagent.dom :as rdom]
            [auto-ap.events :as events]
            [auto-ap.subs :as subs]
            [auto-ap.entities.clients :as client]
            [auto-ap.views.components.layouts :refer [side-bar-layout]]
            [auto-ap.views.components.invoices.side-bar :refer [invoices-side-bar]]
            [auto-ap.views.utils :refer [dispatch-event bind-field with-user]]
            [auto-ap.utils :refer [by]]
            [auto-ap.entities.vendors :as vendor]
            [auto-ap.views.components.typeahead :refer [typeahead-v3]]
            [auto-ap.views.components.invoice-table :refer [invoice-table] :as invoice-table]
            [cljs.reader :as edn]
            [clojure.string :as str]
            [vimsical.re-frame.cofx.inject :as inject]
            [auto-ap.status :as status]
            [vimsical.re-frame.fx.track :as track]
            [dropzone :as dz]
            [auto-ap.views.pages.data-page :as data-page]
            [clojure.set :as set]
            [auto-ap.effects.forward :as forward]))


(defn dropzone []
  (let [client (re-frame/subscribe [::subs/client])
        token (re-frame/subscribe [::subs/token])
        vendor (reagent/atom nil)]
    (reagent/create-class
     {:display-name "dropzone"
      :component-did-mount (fn [this]
                             (dz. (rdom/dom-node this)
                                        (clj->js {:init (fn []
                                                          (let [^js/Dropzone t (js-this)]
                                                            (.on t "addedfiles"
                                                                 (fn []
                                                                   (re-frame/dispatch [::status/completed ::import])))

                                                            (.on t "success" (fn [_ files]
                                                                                           (re-frame/dispatch [::invalidated])))
                                                            (.on t "error" (fn [_ error]
                                                                                         (re-frame/dispatch [::status/error ::import [(edn/read-string error)]])))))
                                                  :paramName "file"
                                                  :headers {"Authorization" (str "Token " @token)}
                                                  :url (str "/api/invoices/upload"
                                                            (when-let [client-name (-> @client :id)]
                                                              (str "?client=" client-name)))
                                                  :previewsContainer "#dz-hidden"
                                                  :previewTemplate "<div class='dz-hidden-preview'></div>"})))
      :reagent-render (fn []
                        {:key batch}
                        [:form.dz {:action "/api/invoices/upload"}
                         [:div.field.has-addons
                          [:p.control
                           [:a.button.is-static "Force Location"]]
                          [:p.control 
                           [:input.input {:name "location" :placeholder "SG" :size "4" :maxlength "2" :style {:display "inline"}}]]]
                         [:div.field.has-addons
                          [:p.control
                           [:a.button.is-static "Force vendor"]]
                          [:div.control {:style {:width "400px"}}
                           [typeahead-v3 {:entities-by-id @(re-frame/subscribe [::subs/vendors-by-id])
                                          :entity-index @(re-frame/subscribe [::subs/searchable-vendors-index])
                                          :entity->text :name
                                          :name "vendor"
                                          :type "typeahead-v3"
                                          :on-change (fn [v]
                                                       (reset! vendor v))
                                          :value @vendor}]]
                          ]
                         [:div.tile.notification
                          [:div.has-text-centered {:style {:padding "80px 0px" :width "100%"}}
                           [:span
                            [:span {:class "icon"}
                             [:i {:class "fa fa-cloud-download"}]]
                            "Drop any invoices you want to process here"]]]])})
    ))




(re-frame/reg-sub
 ::batch
 (fn [db]
   (-> db (::batch 0))))

(re-frame/reg-event-fx
 ::invalidated
 (fn [{:keys [db]} [_ params]]
   {:dispatch-n [[::params-change @(re-frame/subscribe [::data-page/params :import-invoices])]
                 [::data-page/reset-checked :import-invoices]]
    :db (update db ::batch inc)}))

(re-frame/reg-event-fx
 ::mounted
 (fn [cofx [_ params]]
   {::track/register [{:id ::params
                       :subscription [::data-page/params :import-invoices]
                       :event-fn (fn [params]
                                   [::params-change params])}
                      ]
    ::forward/register [{:id ::received
                         :events #{::data-page/received}
                         :event-fn (fn [[_ _ {:keys [data]}]]
                                     [::received data])}]}))

(re-frame/reg-event-fx
 ::unmounted
 (fn [cofx [_ params]]
   {::track/dispose {:id ::params}
    :dispatch [::data-page/dispose :import-invoices]}))


(re-frame/reg-event-fx
 ::params-change
 [with-user]
 (fn [{:keys [user] } [_ params]]
   {:graphql {:token user
              :owns-state {:single [::data-page/page :import-invoices]}
              :query-obj (invoice-table/query (assoc params :import-status "pending"))
              :on-success (fn [result]
                            (let [result (set/rename-keys (first (:invoice-page result))
                                                          {:invoices :data})]

                              [::data-page/received :import-invoices result]))}}))

(re-frame/reg-event-fx
 ::received
 (fn [_ [_ data]]
   {:dispatch [::data-page/toggle-check :import-invoices (by :id data)]}))

(re-frame/reg-event-fx
 ::reject-invoices-clicked
 (fn  [{:keys [db]} [_ invoices on-success]]
   {:graphql
    {:token (-> db :user)
     :owns-state {:single ::reject}
     :query-obj {:venia/operation {:operation/type :mutation
                                   :operation/name "RejectInvoices"}
                 :venia/queries [[:reject-invoices
                                  {:invoices (vec invoices)}
                                  []]]}
     :on-success [::invalidated]}}))

(re-frame/reg-event-fx
 ::approve-invoices-clicked
 (fn  [{:keys [db]} [_ invoices on-success]]
   {:graphql
    {:token (-> db :user)
     :owns-state {:single ::approve}
     :query-obj {:venia/operation {:operation/type :mutation
                                   :operation/name "ApproveInvoices"}
                 :venia/queries [[:approve-invoices
                                  {:invoices (vec invoices)}
                                  []]]}
     :on-success [::invalidated]}}))

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

(defn approve-reject-button [checked]
  [:div.buttons
   [:button.button.is-primary {:on-click (dispatch-event [::approve-invoices-clicked checked])
                               :class (status/class-for @(re-frame/subscribe [::status/single ::approve]))
                               :disabled (or (not (boolean (seq checked)))
                                             (status/disabled-for @(re-frame/subscribe [::status/single ::approve])))}
    "Approve "
    (when (> (count checked ))
      (str 
       (count checked)
       " invoices"))
    [:span " "]]
   [:button.button.is-warning {:on-click (dispatch-event [::reject-invoices-clicked checked])
                               :class (status/class-for @(re-frame/subscribe [::status/single ::reject]))
                               :disabled (or (not (boolean (seq checked)))
                                             (status/disabled-for @(re-frame/subscribe [::status/single ::reject])))}
    "Reject "
    (when (> (count checked ))
      (str 
       (count checked)
       " invoices"))
    [:span " "]]])

(def import-invoices-content
  (with-meta
    (fn []
      (let [page @(re-frame/subscribe [::data-page/page :import-invoices])
            batch @(re-frame/subscribe [::batch])
            client (:id @(re-frame/subscribe [::subs/client]))]
        ^{:key (str client "-" batch)}
        [:div
         [:h1.title "Upload invoices"]
         [status/status-notification {:statuses [[::status/single ::approve]
                                                 [::status/single ::reject]
                                                 [::status/single ::import]]}]
         ^{:key (str batch)}
         [dropzone]
         [:div.mb-4]
         [:div {:class "card found-invoices",}
          [:div {:class "card-header"}
           [:span {:class "card-header-title"} "Found Invoices"]]
          [:div {:class "card-content"}
           [approve-reject-button (:checked-set page)]
           (if (seq (:data (:data page)))
             [invoice-table {:id :approved
                             :data-page :import-invoices
                             :overrides {:client (fn [row]
                                                   [:p (:name (:client row))
                                                    [:p [:i.is-size-7 (:client-identifier row)]]])}
                             :check-boxes true}]
             [:span "No pending invoices"])]]]))
    {:component-did-mount (fn []
                             (re-frame/dispatch-sync [::mounted]))
     :component-will-unmount (fn []
                             (re-frame/dispatch-sync [::unmounted]))}))

(defn import-invoices-page []
  [side-bar-layout {:side-bar [invoices-side-bar {}]
                    :main [import-invoices-content ]}])


