(ns iol-ion.tx.upsert-sales-summary-ledger
  (:require [datomic.api :as dc]))

(defn summary->journal-entry [db summary-id]
  (let [summary (dc/pull db '[:sales-summary/client
                              :sales-summary/date
                              {:sales-summary/items [:sales-summary-item/category
                                                     :ledger-mapped/account
                                                     :ledger-mapped/amount
                                                     {:ledger-mapped/ledger-side [:db/ident]}]}]
                         summary-id)
        items (:sales-summary/items summary)
        aggregated (->> items
                        (filter :ledger-mapped/account)
                        (group-by :ledger-mapped/account)
                        (map (fn [[account acc-items]]
                               (reduce
                                (fn [m item]
                                  (update m (:db/ident (:ledger-mapped/ledger-side item)) (fnil + 0.0) (:ledger-mapped/amount item 0.0)))
                                {:account account}
                                acc-items))))
        _ (clojure.pprint/pprint aggregated)
        line-items (mapv (fn [{:keys [account] :as m}]
                           (cond-> {:db/id (str (java.util.UUID/randomUUID))
                                    :journal-entry-line/account account
                                    :journal-entry-line/location "A"}
                             (get m :ledger-side/debit) (assoc :journal-entry-line/debit (get m :ledger-side/debit))
                             (get m :ledger-side/credit) (assoc :journal-entry-line/credit (get m :ledger-side/credit))))
                         aggregated)
        
        total-debits (reduce + 0.0 (map #(get % :ledger-side/debit 0.0) aggregated))
        total-credits (reduce + 0.0 (map #(get % :ledger-side/credit 0.0) aggregated))
_ (clojure.pprint/pprint [total-debits total-credits])
        ]
    (when (and (seq line-items)
               (= (Math/round (* 1000 total-debits))
                  (Math/round (* 1000 total-credits))))
      {:journal-entry/source "sales-summary"
       :journal-entry/client (:db/id (:sales-summary/client summary))
       :journal-entry/date (:sales-summary/date summary)
       :journal-entry/original-entity summary-id
       :journal-entry/amount total-debits
       :journal-entry/line-items line-items})))

(defn current-date [db]
  (let [last-tx (dc/t->tx (dc/basis-t db))
        [[date]] (seq (dc/q '[:find ?ti :in $ ?tx
                              :where [?tx :db/txInstant ?ti]]
                            db
                            last-tx))]
    date))

(defn upsert-sales-summary [db summary]
  (let [upserted-summary [[:upsert-entity summary]]
        db-after (-> (dc/with db upserted-summary) :db-after)
        summary-id (:db/id summary)
        client-id (-> (dc/pull db-after [{:sales-summary/client [:db/id]}] summary-id)
                      :sales-summary/client
                      :db/id)
        journal-entry (summary->journal-entry db-after summary-id)]
    upserted-summary
    #_(into upserted-summary
          (if journal-entry
            [[:upsert-ledger journal-entry]]
            (concat
             [[:db/retractEntity [:journal-entry/original-entity (:db/id summary)]]]


             (when client-id [{:db/id client-id
                               :client/ledger-last-change (current-date db)}]))))))
