(ns auto-ap.ssr.company
  (:require [amazonica.aws.s3 :as s3]
            [auto-ap.datomic :refer [conn pull-attr]]
            [auto-ap.datomic.clients :refer [full-read]]
            [auto-ap.graphql.utils :refer [assert-can-see-client]]
            [auto-ap.permissions :as permissions]
            [auto-ap.solr :as solr]
            [auto-ap.ssr-routes :as ssr-routes]
            [auto-ap.ssr.components :as com]
            [auto-ap.ssr.hx :as hx]
            [auto-ap.ssr.svg :as svg]
            [auto-ap.ssr.ui :refer [base-page]]
            [auto-ap.ssr.utils :refer [html-response]]
            [bidi.bidi :as bidi]
            [cemerick.url :as url]
            [clojure.java.io :as io]
            [clojure.string :as str]
            [config.core :refer [env]]
            [datomic.api :as dc]
            [ring.middleware.json :refer [wrap-json-response]])
  (:import [java.util UUID]
           (org.apache.commons.codec.binary Base64)))

(defn please-select-client-screen* []
  [:div.grid.grid-cols-3
   (com/content-card {}
                     [:div.col-span-1.p-4 {:class "p-4 sm:p-6"}
                      [:h3 {:class "mb-4 text-xl font-semibold dark:text-white"}
                       "Please select a company"]])])

(defn signature [request]
  (let [signature-file (pull-attr (dc/db conn) :client/signature-file (:db/id (:client request)))]
    (com/content-card {:class " w-[748px]"
                       :hx-target "this"
                       :hx-swap "outerHTML"}
                      [:div.col-span-1.p-4 {:class "p-4 sm:p-6 space-y-4 overflow-visible "
                                            }
                       [:h3 {:class "mb-4 text-xl font-semibold dark:text-white"}
                        "Signature"]
                       [:div#signature-notification.notification.block {:style {:display "none"}}]
                       [:div  {:x-data (hx/json {"signature" nil
                                                              "editing" false
                                                              "existing" (boolean signature-file)})
                                            :hx-put (bidi/path-for ssr-routes/only-routes
                                                                   :company-update-signature)
                                            :hx-trigger "accepted"
                                            :hx-vals "js:{signatureData: event.detail.signatureData}"}
                        [:div.htmx-indicator
                         [:div.bg-gray-100.flex.items-center.text-green-500.justify-center.rounded.rounded-lg.border.border-gray-400 {:style {:width "696px" :height "261px"}}
                          (svg/spinner {:class "w-4 h-4 text-primary-300"})
                          [:div.ml-3 "Loading..."]]]

                        [:div.htmx-indicator-hidden
                         (when signature-file
                           [:img.rounded.rounded-lg.border.border-gray-300.bg-gray-50 {:src signature-file
                                                                                       :width 696
                                                                                       :height 261
                                                                                       :x-show "existing && !editing"}])
                         [:canvas.rounded.rounded-lg.border.border-gray-300


                          {:style {:width 696
                                   :height 261}
                           :x-init "signature= new SignaturePad($el); signature.off()"
                           ":class" "editing ? 'bg-white' : 'bg-gray-50' "
                           :width 696
                           :height 261
                           :x-show "existing ? editing: true"}]]


                        [:div.flex.gap-2.justify-end
                         (com/button {:color :primary
                                      :x-show "!editing"
                                      "@click" "signature.clear(); signature.on(); editing=true;"}
                                     "New signature")
                         (com/button {:color :primary
                                      :x-show "editing"
                                      "@click" "signature.clear();"}
                                     "Clear")

                         (com/button {:color :primary
                                      "@click" "$data.signatureData=signature.toDataURL('image/png'); signature.off(); editing=false;  $dispatch('accepted', {signatureData: $data.signatureData}) "
                                      :x-show "editing"}
                                     "Accept")]]

                       [:div 
                        [:div.flex.justify-center " - or -"]
                        [:form {:hx-post (bidi/path-for ssr-routes/only-routes
                                                        :company-upload-signature)
                                :hx-disinherit "hx-vals"
                                :hx-encoding "multipart/form-data"
                                #_#_:hx-target "#signature-notification"
                                :hx-swap "outerHTML"
                                :id     "upload"
                                :hx-trigger "z"
                                }
[:div.htmx-indicator
 [:div.bg-gray-100.flex.items-center.text-green-500.justify-center.rounded.rounded-lg.border.border-gray-400 {:style {:width "696px" :height "261px"}}
  (svg/spinner {:class "w-4 h-4 text-primary-300"})
  [:div.ml-3 "Loading..."]]]
[:div.htmx-indicator-hidden
 [:div.border-2.border-dashed.rounded-lg.p-4.w-full.text-center.cursor-pointer.h-64.flex.items-center.justify-center.text-lg.relative
  {:x-data (hx/json {"files" nil
                     "hovering" false})
   :x-dispatch:z "files"
   ":class" "{'bg-blue-100': !hovering,
                                                           'border-blue-300': !hovering,
                                                           'text-blue-700': !hovering,
                                                           'bg-green-100': hovering,
                                                           'border-green-300': hovering,
                                                           'text-green-700': hovering
                                                          }"}



  [:input {:type "file"
           :name "file"
           :class "absolute inset-0 m-0 p-0 w-full h-full outline-none opacity-0",
           :x-on:change "files = $event.target.files;",
           :x-on:dragover "hovering = true",
           :x-on:dragleave "hovering = false",
           :x-on:drop "hovering = false"}]
  [:div.flex.flex-col.space-2
   [:div
    [:ul {:x-show "files != null"}
     [:template {:x-for "f in files"}
      [:li (com/pill {:color :primary :x-text "f.name"})]]]]


   [:div.htmx-indicator-hidden "Drop a signature file (696x261 pixels jpeg) here."]]]] ]]])))

(defn upload-signature-data [{{:strs [signatureData]} :form-params client :client :as request}]
  (let [prefix "data:image/png;base64,"]
    (when signatureData
      (when-not (str/starts-with? signatureData prefix)
        (throw (ex-info "Invalid signature image" {:validation-error (str "Invalid signature image.")})))
      (let [signature-id (str (UUID/randomUUID))
            raw-bytes (Base64/decodeBase64 (subs signatureData (count prefix)))]
        (s3/put-object :bucket-name "integreat-signature-images" #_(:data-bucket env)
                       :key (str signature-id ".png")
                       :input-stream (io/make-input-stream raw-bytes {})
                       :metadata {:content-type "image/png"
                                  :content-length (count raw-bytes)}
                       :canned-acl "public-read")
        @(dc/transact conn [{:db/id (:db/id client)
                             :client/signature-file (str "https://integreat-signature-images.s3.amazonaws.com/" signature-id ".png")}])
        (html-response
         (signature request))))))

(defn upload-signature-file [{{:strs [signatureData]} :form-params client :client user :identity :as request}]
  (assert-can-see-client user client)
  (let [{:strs [file]} (:multipart-params request) ]
(try
          (let [signature-id (str (UUID/randomUUID)) ]
            (s3/put-object :bucket-name "integreat-signature-images" #_(:data-bucket env)
                           :key (str signature-id ".jpg")
                           :input-stream (io/input-stream (:tempfile file))
                           :metadata {:content-type "image/jpeg"
                                      :content-length (:length (:tempfile file))}
                           :canned-acl "public-read")
            @(dc/transact conn [{:db/id (:db/id client)
                                 :client/signature-file (str "https://integreat-signature-images.s3.amazonaws.com/" signature-id ".jpg")}])
            (html-response
             (signature request)))
          (catch Exception e
            (println e)
            #_(-> result
                (assoc :error? true)
                (update :results conj {:filename filename
                                       :response (.getMessage e)
                                       :sample (:sample (ex-data e))
                                       :template (:template (ex-data e))}))))
    #_(html-response [:div#page-notification.p-4.rounded-lg
                    {:class (if (:error? results)
                              "bg-red-50 text-red-700"
                              "bg-primary-50 text-primary-700")}
                    [:table
                     [:thead
                      [:tr [:td "File"] [:td "Result"]
                       [:td "Template"]
                       (if (:error? results)
                         [:td "Sample match"])]
                      #_[:tr "Result"]
                      #_[:tr "Template"]]
                     (for [r (:results results)]
                       [:tr
                        [:td.p-2.border
                         {:class (if (:error? results)
                                   "bg-red-50 text-red-700 border-red-300"
                                   "bg-primary-50 text-primary-700 border-green-500")}
                         (:filename r)]
                        [:td.p-2.border
                         {:class (if (:error? results)
                                   "bg-red-50 text-red-700 border-red-300"
                                   "bg-primary-50 text-primary-700 border-green-500")}
                         (:response r)]
                        [:td.p-2.border
                         {:class (if (:error? results)
                                   "bg-red-50 text-red-700 border-red-300"
                                   "bg-primary-50 text-primary-700 border-green-500")}
                         "Template: " (:template r)]
                        (if (:error? results)
                          [:td.p-2.border
                           {:class "bg-red-50 text-red-700 border-red-300"}

                           [:ul
                            (for [[k v] (dissoc (:sample r) :template :source-url :full-text :text)]
                              [:li (name k) ": " (str v)])]
                           #_(:template r)])])]]
                   :headers
                   {"hx-trigger" "invalidated"})))

(defn main-content* [{:keys [client identity] :as request}]
  (if-not client
    (please-select-client-screen*)
    (let [client (dc/pull (dc/db conn) full-read (:db/id client))]
      [:div
       [:div.grid.grid-cols-3.gap-4
        (com/content-card {}
                          [:div.col-span-1.p-4 {:class "p-4 sm:p-6"}
                           [:h3 {:class "mb-4 text-xl font-semibold dark:text-white"}
                            (:client/name client)]
                           (when-let [address (-> client :client/address)]
                             [:div.flex.flex-col.gap-1.text-lg.dark:text-white.text-gray-700
                              [:p (-> address :address/street1)]
                              [:p (-> address :address/street2)]
                              [:p (-> address :address/city) " "
                               (-> address :address/state) ", "
                               (-> address :address/zip)]])])
        (com/content-card {}
                          [:div.col-span-1.p-4 {:class "p-4 sm:p-6"}
                           [:h3 {:class "mb-4 text-xl font-semibold dark:text-white"}
                            "Downloads"]
                           [:a {:href (str (assoc (url/url (str (:base-url env) "/api/vendors/company/export"))
                                                  :query {"client" (:client/code client)}))}
                            (com/button {:color :primary}
                                        "Download vendor list"
                                        (com/button-icon {} svg/download))]])
        [:div]]
       (when (permissions/can? identity {:client client :subject :signature :activity :edit})
         (signature request))])))

(defn page [{:keys [identity matched-route] :as request}]
  (base-page
   request
   (com/page {:nav           com/company-aside-nav
              :client-selection (:client-selection request)
              :request request
              :client (:client request)
              :clients (:clients request)
              :identity      (:identity request)
              :app-params {:hx-get     (bidi/path-for ssr-routes/only-routes
                                                      :company)
                           :hx-trigger "clientSelected from:body"
                           :hx-select "#app-contents"
                           :hx-swap    "outerHTML swap:300ms"}}
             (com/breadcrumbs {}
                              [:a {:href (bidi/path-for ssr-routes/only-routes
                                                        :company)}
                               "My Company"])
             (main-content* request))
   "My Company"))

(defn search [{:keys [clients query-params]}]
  (let [valid-client-ids (set (map :db/id clients))
        name-like-ids    (when (not-empty (get query-params "q"))
                           (set (map (comp #(Long/parseLong %) :id)
                                     (solr/query solr/impl "clients"
                                                 {"query"  (format "_text_:(%s*)" (str/upper-case (solr/escape (get query-params "q"))))
                                                  "fields" "id"
                                                  "limit"  300}))))
        valid-clients    (for [n     name-like-ids
                               :when (valid-client-ids n)]
                           {"value" n "label" (pull-attr (dc/db conn) :client/name n)})]
    {:body (take 10 valid-clients)}))

(def search (wrap-json-response search))


(defn bank-account-search [{:keys [route-params query-params clients]}]
  (let [valid-client-ids (set (map :db/id clients))
        selected-client-id (Long/parseLong (get route-params :db/id))
        bank-accounts (when (valid-client-ids selected-client-id)
                        (->> (dc/pull (dc/db conn) [{:client/bank-accounts [:db/id :bank-account/name]}]
                                      selected-client-id)
                             :client/bank-accounts
                             (filter (fn [{:keys [bank-account/name]}]
                                       (str/includes? (or (some-> name str/upper-case) "")
                                                      (or (some-> query-params
                                                                  (get "q")
                                                                  str/upper-case)
                                                          "__"))))
                             (map (fn [{:keys [db/id bank-account/name]}]
                                    {"value" id "label" name}))))]
    {:body (take 10 bank-accounts)}))

(def bank-account-search (wrap-json-response bank-account-search))

(defn bank-account-typeahead* [{:keys [client-id name value]}]
  (if client-id
    (com/typeahead {:name        name
                    :class       "w-96"
                    :placeholder "Search..."
                    :url         (bidi/path-for ssr-routes/only-routes :bank-account-search
                                                :db/id client-id)
                    :value       value
                    :value-fn    (some-fn :db/id identity)
                    :content-fn  (some-fn :bank-account/name #(pull-attr (dc/db conn) :bank-account/name %))})
    [:span.text-xs.text-gray-500 "Please select a client before selecting a bank account."
     [:input {:type "hidden"
              :name name}]]))

(defn bank-account-typeahead [{:keys [query-params clients]}]
  (html-response (bank-account-typeahead* {:client-id ((set (map :db/id clients))
                                                       (some->> "client-id"
                                                                (get query-params)
                                                                not-empty
                                                                Long/parseLong))
                                           :name (get query-params "name")})))
