(ns auto-ap.views.pages.ledger.profit-and-loss-detail
  (:require
   [auto-ap.forms :as forms]
   [auto-ap.forms.builder :as form-builder]
   [auto-ap.ledger.reports :as l-reports]
   [auto-ap.status :as status]
   [auto-ap.subs :as subs]
   [auto-ap.views.components :as com]
   [auto-ap.views.components.buttons :as buttons]
   [auto-ap.views.components.layouts :refer [side-bar-layout]]
   [auto-ap.views.components.modal :as modal]
   [auto-ap.views.pages.ledger.report-table :as rtable]
   [auto-ap.views.pages.ledger.side-bar :refer [ledger-side-bar]]
   [auto-ap.views.utils
    :refer [date->str date-picker dispatch-event query-params standard with-user local-now]]
   [cljs-time.core :as t]
   [clojure.string :as str]
   [re-frame.core :as re-frame]
   [react-dom :as react-dom]
   [reagent.core :as reagent]
   [vimsical.re-frame.cofx.inject :as inject]))


(defn encode-period [p]
  {:start (date->str (:start p) standard)
   :end (date->str (:end p) standard)})


;; SUBS 

(re-frame/reg-event-db
 ::received
 [(forms/in-form ::form)]
 (fn [db [_ data]]
   (-> db (assoc :report (:journal-detail-report data)))))

;; EVENTS

(re-frame/reg-event-fx
 ::report-requested
 [with-user (forms/in-form ::form)]
 (fn [{:keys [db user]}]
   (cond-> {:graphql {:token user
                      :owns-state {:single ::page}
                      :query-obj {:venia/queries [[:journal-detail-report
                                                   {:client-ids          (map (comp :id :client) (:clients (:data db)))
                                                    :date-range            {:start (date->str  (:start (:date-range (:data db))) standard)
                                                                            :end (date->str  (:end (:date-range (:data db))) standard)}
                                                    :categories [:sales
                                                                 :cogs
                                                                 :payroll
                                                                 :controllable
                                                                 :fixed-overhead
                                                                 :ownership-controllable]}
                                                   [[:categories [[:journal-entries [:description
                                                                                     :date
                                                                                     :debit :credit :location :running-balance
                                                                                     [:account [:id :name]]]]
                                                                  :category
                                                                  :total
                                                                  :client-id
                                                                  :location
                                                                  [:account [:numeric-code :name]]]]]]]}
                      :on-success [::received]}
            :set-uri-params {:date-range (encode-period (:date-range (:data db)))
                             :clients (mapv #(select-keys (:client %) [:name :id]) (:clients (:data db))) }
            :db (-> db
                    (dissoc :report)
                    (update-in [:data :clients] #(into [] (filter seq %))))})))

(defn email-body [report-url]
  (js/encodeURIComponent
    (str
      "Hello,
Click here (" report-url ") to download your financial reports. We have not finished reviewing and reconciling these numbers with you. Please review and let us know if anything seems missing or in need of correction.
Click here (http://app.integreatconsult.com/) to login to the Financials app to review the details here.
Click here (https://share.vidyard.com/watch/MHTo5PyXPxXUpVH93RWFM9?) for a video on how to run a P&L on your own.
To see a history of past financial reports, click here: https://app.integreatconsult.com/reports/

NOTE: Please review the transactions we may have question for you here: https://app.integreatconsult.com/transactions/requires-feedback. You can either edit the transaction to what expense account it should be or email back what it should be.")))

(re-frame/reg-event-fx
  ::received-pdf
  [(re-frame/inject-cofx ::inject/sub [::subs/clients-by-id])]
  (fn [{:keys [db ::subs/clients-by-id]} [_ result]]
    (let [selected-clients (-> db ::forms/forms ::form :data :clients)
          single-client? (= (count selected-clients)
                            1)
          client-emails (when single-client?
                         (-> clients-by-id
                             (get (:id (:client (first selected-clients))))
                             :emails))]
      {:dispatch [::modal/modal-requested {:title "Your report is ready"
                                           :body  [:div
                                                   [:div "Click "
                                                    [:a {:href (-> result :journal-detail-report-pdf :url) :target "_new"} "here"] " to view it."]
                                                   (when (and single-client? (seq client-emails) @(re-frame/subscribe [::subs/is-admin?]))
                                                     [:div "Once you've confirmed you're happy with it, click "
                                                      [:a {:href (str "mailto:" (str/join ";" (map :email client-emails)) "?body=" (email-body (-> result :journal-detail-report-pdf :url))
                                                                      "&subject=" (-> result  :journal-detail-report-pdf :name) " is ready")}
                                                       "here"] " to open your email client and to send it to " (str/join "," (map (fn [e]
                                                                                                                                    (str (:email e) " (" (:description e) ")"))
                                                                                                                                  client-emails)) "."])]}]})))
(re-frame/reg-event-fx
 ::export-pdf
 [with-user (forms/in-form ::form)]
 (fn [{:keys [db user]}]
   (cond-> {:graphql {:token user
                      :owns-state {:single ::page}
                      :query-obj {:venia/queries [[:journal-detail-report-pdf
                                                   {:client-ids (map (comp :id :client) (:clients (:data db)))
                                                    :date-range {:start (date->str  (:start (:date-range (:data db))) standard)
                                                                 :end   (date->str  (:end (:date-range (:data db))) standard)}
                                                    :categories [:sales
                                                                 :cogs
                                                                 :payroll
                                                                 :controllable
                                                                 :fixed-overhead
                                                                 :ownership-controllable]}
                                                   [:url :name]]]} 
                      :on-success [::received-pdf]}
            :set-uri-params {:date-range (:date-range (:data db))
                             :clients    (mapv #(select-keys (:client %) [:name :id]) (:clients (:data db))) }
            :db (dissoc db :report)})))


(re-frame/reg-event-fx
  ::change
  [with-user (forms/in-form ::form)]
  (fn [{:keys [db]} [_ & event]]
    {:db (dissoc db :report)
     :dispatch (into [::forms/change ::form] event)}))

(defn report-control-detail [{:keys [active box which]} children]
  (when (and @box
             (= which @active)) 
    (react-dom/createPortal (reagent/as-element
                             [:div.notification.is-light
                              [:a.delete {:on-click (fn [] (reset! active nil))}]
                              children
                              ])
                            @box)))


(defn report-controls []
  (let [!box   (atom nil)
        active (reagent/atom nil)]
    (fn []
      (let [{:keys [data]}                                                       @(re-frame/subscribe [::forms/form ::form])
            {:keys []} data]
        [form-builder/builder {:change-event [::change]
                               :submit-event [::report-requested]
                               :id           ::form}
         [:div.report-controls
          [:div.level.mb-2
           [:div.level-left
            [:div.level-item
             [buttons/dropdown {:on-click (fn [] (reset! active :clients))}
              [:span (str "Companies"
                          (when-let [clients (:clients data)] 
                            (str " (" (str/join ", " (map (comp :name :client) clients)) ")")))]]
             [report-control-detail {:active active :box !box :which :clients}
              [:div {:style {:width "20em"}}
               [:h4.subtitle "Companies"]
               [form-builder/raw-field-v2 {:field :clients}
                [com/multi-field-v2 {:new-text "Add another company"
                                     :template [[form-builder/raw-field-v2 {:field :client}
                                                 [com/entity-typeahead {:entities     @(re-frame/subscribe [::subs/clients])
                                                                        :style        {:width "18em"}
                                                                        :entity->text :name}]]]
                                     :key-fn :id}]]]]]
            [:div.level-item
             "From"]
            [:div.level-item
             [form-builder/raw-field-v2 {:field [:date-range :start]}
              [date-picker {:output :cljs-date}]]]
            [:div.level-item
             " To "]
            [:div.level-item
             [form-builder/raw-field-v2 {:field [:date-range :end]}
              [date-picker {:output :cljs-date}]]]
           [:div.level-right
            [:div.buttons 
             [:button.button.is-secondary {:on-click (dispatch-event [::export-pdf])} "Export"]
             [:button.button.is-primary "Run"]]]]]
          [:div.report-control-detail {:ref (fn [el]
                                              (when (not= @!box el)
                                                (reset! !box el)))}]]]))))

(defn pnl-detail-report [{:keys [args report-data]}]
  (let [client-codes (->> @(re-frame/subscribe [::subs/clients-by-id])
                                 (map (fn [[k v]]
                                        [k (:code v)]))
                                 (into {}))
        report       (l-reports/journal-detail-report args report-data client-codes)]
    [:div
     [:h1.title "Profit and Loss Detail - " (str/join ", " (map (comp :name :client) (:clients args)))]
     (when (:warning report)
       [:div.notification.is-warning.is-light
        (:warning report)])
     [rtable/table {:widths [20 10 20 8 8 8]
                    :table  report}]]))


;; TODO Break out one category per location
;; TODO filter ledger entry lines to only ones that match
;; TODO Render them!
(defn profit-and-loss-content []
  (let [status                @(re-frame/subscribe [::status/single ::page])
        {:keys [data report]} @(re-frame/subscribe [::forms/form ::form])]
    [:div 
     [:div
      [status/status-notification {:statuses [[::status/single ::page]]}]
      [report-controls]]
     [status/big-loader status]
     (when (and (not= :loading (:state status))
                report)
       [pnl-detail-report {:report-data report
                           :args        data}])]))


(re-frame/reg-event-fx
 ::mounted-pnl
 (fn [{:keys [db]} _]
   (let [qp (query-params)]
     {:db (forms/start-form db ::form {:date-range     {:end (local-now)
                                                        :start (t/minus (local-now) (t/weeks 2))}
                                       :clients        (mapv (fn [c] {:client c :id (random-uuid)})
                                                      (or (:clients qp)
                                                          [(some-> @(re-frame/subscribe [::subs/client]) (select-keys [:name :id]) )]))})
      :dispatch [::status/dispose-single ::page]})))

(defn profit-and-loss-detail-page []
  (reagent/create-class
   {:display-name "profit-and-loss-detail-page"
    :component-did-mount #(re-frame/dispatch [::mounted-pnl])
    :reagent-render
    (fn []
      (let [user (re-frame/subscribe [::subs/user])]
        (if (not= "manager" (:user/role @user))
          [side-bar-layout
           {:side-bar [ledger-side-bar] 
            :main [profit-and-loss-content]}]
          [:div "Not authorized"])))}))
