(ns auto-ap.integration.graphql.invoices
  (:require
   [auto-ap.time-reader]
   [auto-ap.datomic :refer [conn]]
   [auto-ap.graphql.invoices :as sut]
   [clojure.test :as t :refer [deftest is testing use-fixtures]]
   [auto-ap.integration.util
    :refer [admin-token
            setup-test-data
            test-account
            test-invoice
            test-vendor
            wrap-setup]]
   [datomic.api :as d]))
(use-fixtures :each wrap-setup)

(deftest test-add-invoice
  (testing "It should Add an invoice"
    (let [{:strs [test-vendor-id test-client-id test-account-id
                  denied-account-id vendor-account-id vendor-with-special-account]}
          (setup-test-data [(test-account :db/id "denied-account-id"
                                          :account/invoice-allowance :allowance/denied)
                            (test-account :db/id "vendor-account-id"
                                          :account/invoice-allowance :allowance/denied
                                          :account/vendor-allowance :allowance/allowed)
                            (test-vendor :db/id "vendor-with-special-account"
                                         :vendor/default-account "vendor-account-id")])]
      (is (some? (sut/add-invoice {:id (admin-token)}
                                  {:invoice {:client_id        test-client-id
                                             :vendor_id        test-vendor-id
                                             :invoice_number   "123"
                                             :date             #clj-time/date-time "2022-01-01"
                                             :total            10.00
                                             :expense_accounts [{:amount     10.0
                                                                 :location   "DT"
                                                                 :account_id test-account-id}]}}
                                  nil)))
      (testing "It should prevent an expense account that isn't allowed"
        (is (thrown? Exception (sut/add-invoice {:id (admin-token)}
                                                {:invoice {:client_id        test-client-id
                                                           :vendor_id        test-vendor-id
                                                           :invoice_number   "789"
                                                           :date             #clj-time/date-time "2022-01-01"
                                                           :total            10.00
                                                           :expense_accounts [{:amount     10.0
                                                                               :location   "DT"
                                                                               :account_id denied-account-id}]}}
                                                nil))))

      (testing "It should allow an expense account that is valid for the vendor"
        (is (some? (sut/add-invoice {:id (admin-token)}
                                    {:invoice {:client_id        test-client-id
                                               :vendor_id        vendor-with-special-account
                                               :invoice_number   "456"
                                               :date             #clj-time/date-time "2022-01-01"
                                               :total            10.00
                                               :expense_accounts [{:amount     10.0
                                                                   :location   "DT"
                                                                   :account_id vendor-account-id}]}}
                                    nil)))))))

(deftest edit-invoice
  (testing "It should edit invoices"
    (let [{:strs [invoice-id
                  new-vendor-id
                  new-account-id]}
          (setup-test-data [(test-invoice :db/id "invoice-id")
                            (test-vendor :db/id "new-vendor-id")
                            (test-account :db/id "new-account-id")])]
      (is (some? (sut/edit-invoice {:id (admin-token)}
                                   {:invoice {:id invoice-id
                                              :vendor_id        new-vendor-id
                                              :invoice_number   "890213"
                                              :date             #clj-time/date-time "2023-01-01"
                                              :total            100.00
                                              :outstanding_balance 100.00
                                              :expense_accounts [{:amount     100.0
                                                                  :location   "DT"
                                                                  :account_id new-account-id}]}}
                                  nil)))
      (is (= #:invoice{:invoice-number "890213"
                       :date           #inst "2023-01-01T00:00:00.000-00:00"
                       :total          100.0
                       :expense-accounts
                       [#:invoice-expense-account{:amount   100.0
                                                  :location "DT"
                                                  :account {:db/id new-account-id}}]}
             (d/pull (d/db conn) [:invoice/invoice-number
                                  :invoice/date
                                  :invoice/total
                                  {:invoice/expense-accounts [:invoice-expense-account/amount
                                                              :invoice-expense-account/location
                                                              :invoice-expense-account/account]}]
                     invoice-id)))

      (testing "Should not be able to change vendor"
        (is (not= new-vendor-id (:db/id (:invoice/vendor (d/pull (d/db conn) [:invoice/vendor] invoice-id))))))))

  (testing "Should disallow adding a conflicting invoice"
    (let [{:strs [invoice-id]}
          (setup-test-data [(test-invoice :db/id "invoice-id"
                                          :invoice/invoice-number "original-invoice"
                                          :invoice/vendor "test-vendor-id"
                                          :invoice/client "test-client-id")
                            (test-invoice :db/id "extant-invoice-id"
                                          :invoice/invoice-number "already taken"
                                          :invoice/vendor "test-vendor-id"
                                          :invoice/client "test-client-id")])]
      (is (thrown? Exception (sut/edit-invoice {:id (admin-token)}
                                               {:invoice {:id                  invoice-id
                                                          :invoice_number      "already taken"}}
                                               nil))))))

(deftest edit-expense-accounts
  (testing "It should edit expense accounts"
    (let [{:strs [invoice-id
                  new-account-id]}
          (setup-test-data [(test-invoice :db/id "invoice-id")
                            (test-account :db/id "new-account-id")])]
      (is (some? (sut/edit-expense-accounts {:id (admin-token)}
                                   {:invoice_id invoice-id
                                    :expense_accounts [{:amount 100.0
                                                        :account_id new-account-id
                                                        :location "DT"}]}
                                  nil)))
      (is (= [#:invoice-expense-account{:amount   100.0
                                        :location "DT"
                                        :account  {:db/id new-account-id}}]
             (-> (d/pull (d/db conn) [{:invoice/expense-accounts [:invoice-expense-account/amount
                                                                  :invoice-expense-account/location
                                                                  :invoice-expense-account/account]}]
                         invoice-id)
                 :invoice/expense-accounts))))))

(deftest bulk-change-invoices
  (testing "It should change expense accounts in bulk"
    (let [{:strs [invoice-id
                  new-account-id
                  test-client-id]}
          (setup-test-data [(test-invoice :db/id "invoice-id")
                            (test-account :db/id "new-account-id")])]
      (is (some? (sut/bulk-change-invoices {:id (admin-token)}
                                           {:client_id test-client-id
                                            :filters {:client_id test-client-id}
                                            :accounts [{:percentage     1.0
                                                        :account_id new-account-id
                                                        :location   "Shared"}]}
                                  nil)))
      (is (= [#:invoice-expense-account{:amount   100.0
                                        :location "DT"
                                        :account  {:db/id new-account-id}}]
             (-> (d/pull (d/db conn) [{:invoice/expense-accounts [:invoice-expense-account/amount
                                                                  :invoice-expense-account/location
                                                                  :invoice-expense-account/account]}]
                         invoice-id)
                 :invoice/expense-accounts))))))

(deftest void-invoices
  (testing "It should voide invoices in bulk"
    (let [{:strs [invoice-id test-client-id]}
          (setup-test-data [(test-invoice :db/id "invoice-id"
                                          :invoice/status :invoice-status/unpaid)
                            (test-account :db/id "new-account-id")])]

      (is (some? (sut/void-invoices {:id (admin-token) :clients [{:db/id test-client-id}]}
                                           {:filters {:client_id test-client-id}}
                                  nil)))
      (is (= :invoice-status/voided
             (-> (d/pull (d/db conn) [{:invoice/status [:db/ident]}]
                         invoice-id)
                 :invoice/status
                 :db/ident)))

      (testing "Should unvoid invoice"
        (is (some? (sut/unvoid-invoice {:id (admin-token)}
                                      {:invoice_id invoice-id}
                                      nil)))
        (is (= :invoice-status/unpaid
               (-> (d/pull (d/db conn) [{:invoice/status [:db/ident]}]
                           invoice-id)
                   :invoice/status
                   :db/ident)))))))


(deftest void-invoice
  (testing "It should voide invoices in bulk"
    (let [{:strs [invoice-id]}
          (setup-test-data [(test-invoice :db/id "invoice-id"
                                          :invoice/status :invoice-status/unpaid)
                            (test-account :db/id "new-account-id")])]

      
      (is (some? (sut/void-invoice {:id (admin-token)}
                                    {:invoice_id invoice-id}
                                    nil)))
      (is (= :invoice-status/voided
             (-> (d/pull (d/db conn) [{:invoice/status [:db/ident]}]
                         invoice-id)
                 :invoice/status
                 :db/ident)))

      (testing "Should unvoid invoice"
        (is (some? (sut/unvoid-invoice {:id (admin-token)}
                                      {:invoice_id invoice-id}
                                      nil)))
        (is (= :invoice-status/unpaid
               (-> (d/pull (d/db conn) [{:invoice/status [:db/ident]}]
                           invoice-id)
                   :invoice/status
                   :db/ident)))))))
