(ns auto-ap.views.pages.admin.excel-import
  (:require-macros [cljs.core.async.macros :refer [go]])
  (:require [re-frame.core :as re-frame]
            [reagent.core :as reagent]
            [auto-ap.subs :as subs]
            [auto-ap.events.admin.companies :as events]
            [auto-ap.entities.companies :as entity]
            [auto-ap.views.utils :refer [login-url dispatch-value-change bind-field horizontal-field dispatch-event]]
            [cljs.reader :as edn]
            [auto-ap.routes :as routes]
            [bidi.bidi :as bidi]
            [clojure.string :as str]))

(re-frame/reg-sub
 ::excel-import
 (fn [db]
   (::excel-import db)))

(re-frame/reg-event-db
 ::change
 (fn  [db [_ field v]]
   (assoc-in db (into [::excel-import]  field) v)))

(re-frame/reg-event-db
 ::edit
 (fn  [db [_ field v]]
   (assoc db ::excel-import nil )
   db))

(re-frame/reg-event-fx
 ::save
 (fn [{:keys [db]}]
   (let [excel-import (::excel-import db)]
     {:http {:token (:user db)
             :method :post 
             :body (pr-str excel-import)
             :headers {"Content-Type" "application/edn"}
             :uri (str "/api/invoices/upload-integreat")
             :on-success [::save-complete]
             :on-error [::save-error]}
      :db (-> db
              (assoc-in [::excel-import :rows] nil)
              (assoc-in [::excel-import :saving?] true))})))

(re-frame/reg-event-fx
 ::save-complete
 (fn [{:keys [db]} [_ rows]]
   {:dispatch [::edit nil]
    :db
    (-> db
        (assoc-in [::excel-import :rows] rows)
        (assoc-in [::excel-import :saving?] false))}))

(re-frame/reg-event-fx
 ::save-error
 (fn [{:keys [db]}]
   {:dispatch [::change [:error] true]
    :db (-> db
            (assoc-in [::excel-import :rows] nil)
            (assoc-in [::excel-import :saving?] false))}))

(re-frame/reg-event-db
 ::toggle-vendor
 (fn [db [_ data]]
   (update-in db [::excel-import :create-vendors] (fn [x]
                                            (let [x (or x #{})]
                                              (if (x data)
                                                (disj x data)
                                                (conj x data)))))))
(re-frame/reg-event-fx
 ::create-vendors
 (fn [{:keys [db]}]
   (let [excel-import (::excel-import db)]
     {:https {:requests (map  (fn [v]
                                {:token (:user db)
                                 :method :post 
                                 :body (pr-str {:name v})
                                 :headers {"Content-Type" "application/edn"}
                                 :uri (str "/api/vendors/")})
                              (get-in db [::excel-import :create-vendors]))
              :on-success [::create-vendor-complete]
              :on-error [::create-vendor-error]}
      :db (-> db 
              (assoc-in [::excel-import :saving-vendors?] true))})))


(re-frame/reg-event-db
 ::create-vendor-complete
 (fn [db [_ data]]
   (-> db
       (update-in [::excel-import :rows :vendors-not-found]
                  (fn [v]
                    (reduce disj v (get-in db [::excel-import :create-vendors]))))
       (update-in [::excel-import] dissoc :create-vendors))))

(defn admin-excel-import-page []
  [:div
   (let [{{:keys [vendors-not-found already-imported imported]} :rows
          :keys [create-vendors]
          :or {create-vendors #{}}
          :as excel-import-data} @(re-frame/subscribe [::excel-import])]
     [:div
      [:h1.title "Import Invoices from Integreat Excel"]
      (when (seq vendors-not-found)
        [:article.message.is-warning.is-paddingless
         [:div.message-header
          "Some vendors could not be found"]

         [:div.message-body
          [:h2 "Check the vendors you want to create"]
          [:div.columns
           (for [[i vendor-group] (map vector (range) (partition-all (max 1 (/ (count vendors-not-found) 3)) vendors-not-found))]
             ^{:key i}
             [:div.column
              (for [v vendor-group]
                ^{:key v} [:div.control
                           [:label.checkbox
                            [:input {:value v
                                     :checked (if (create-vendors v)
                                                "checked"
                                                "")

                                     :type "checkbox"
                                     :on-change (fn []
                                                  (re-frame/dispatch [::toggle-vendor v]))}]
                            (str " " v)]])])]
          [:div
           [:button.button.is-pulled-right
            {:on-click (dispatch-event [::create-vendors])
             :disabled (when-not (seq create-vendors)
                         "disabled")
             }
            (str "Create " (count create-vendors) " vendors")]]
          [:div.is-clearfix]]])
      [bind-field
       [:textarea.textarea {:rows "20"
                            :field :excel-rows
                            :type "text"
                            :event ::change
                            :subscription excel-import-data}]]
      
      [:button.button.is-large.is-pulled-right.is-primary  {:on-click (dispatch-event [::save])
                                                            :class (when (:saving? excel-import-data)
                                                                     "is-loading")
                                                            :disabled (when (:saving? excel-import-data) "disabled")} "Import"]
      
      [:div.is-clearfix]
      [:div.is-clearfix
       [:p
        (when imported
          (str imported " rows imported."))]
       [:p
        (when already-imported
          (str already-imported " rows already imported."))]]
      (when-let [errors (:errors (:rows excel-import-data))]
        [:div
         [:h3 (str "Import errors (" (min 100 (count errors)) " / " (count errors) " )")]
         [:table.table.is-fullwidth
          [:thead
           [:th "Date"]
           [:th "Invoice #"]
           [:th "Company"]
           [:th "Vendor"]
           [:th "Amount"]
           [:th "Errors"]]

          (for [{:keys [raw-date invoice-number company vendor-name amount] row-errors :errors} (take 100 errors)]
            ^{:key (str raw-date invoice-number company vendor-name amount)}
            [:tr
             [:td raw-date]
             [:td invoice-number]
             [:td company]
             [:td vendor-name]
             [:td amount]
             [:td (map (fn [{:keys [info]}] ^{:key info} [:p info]) row-errors)]])]])])])
