;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) KALEIDOS INC Sucursal en España SL

(ns app.main.ui.workspace.sidebar.assets.groups
  (:require-macros [app.main.style :as stl])
  (:require
   [app.common.path-names :as cpn]
   [app.common.schema :as sm]
   [app.main.data.modal :as modal]
   [app.main.data.workspace :as dw]
   [app.main.store :as st]
   [app.main.ui.components.forms :as fm]
   [app.main.ui.components.title-bar :refer [title-bar*]]
   [app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
   [app.main.ui.ds.foundations.assets.icon :as i]
   [app.main.ui.icons :as deprecated-icon]
   [app.main.ui.workspace.sidebar.assets.common :as cmm]
   [app.util.dom :as dom]
   [app.util.i18n :as i18n :refer [tr]]
   [rumext.v2 :as mf]))

(mf/defc asset-group-title*
  [{:keys [file-id section path is-group-open on-rename on-ungroup on-delete-group on-group-combine-variants is-can-combine on-add]}]
  (when-not (empty? path)
    (let [[other-path last-path truncated] (cpn/compact-path path 35 true)
          menu-state     (mf/use-state cmm/initial-context-menu-state)
          on-fold-group
          (mf/use-fn
           (mf/deps file-id section path is-group-open)
           (fn [event]
             (dom/stop-propagation event)
             (st/emit! (dw/set-assets-group-open file-id
                                                 section
                                                 path
                                                 (not is-group-open)))))
          on-context-menu
          (mf/use-fn
           (fn [event]
             (dom/prevent-default event)
             (dom/stop-propagation event)
             (let [pos (dom/get-client-position event)]
               (swap! menu-state cmm/open-context-menu pos))))

          on-close-menu
          (mf/use-fn #(swap! menu-state cmm/close-context-menu))]
      [:div {:class (stl/css :group-title-wrapper)}
       [:div {:class (stl/css :group-title)
              :on-context-menu on-context-menu}
        [:> title-bar* {:collapsable    true
                        :collapsed      (not is-group-open)
                        :on-collapsed   on-fold-group
                        :title          (mf/html [:* (when-not (empty? other-path)
                                                       [:span {:class (stl/css :pre-path)
                                                               :title (when truncated path)}
                                                        other-path "\u00A0\u2022\u00A0"])
                                                  [:span {:class (stl/css :path)
                                                          :title (when truncated path)}
                                                   last-path]])}]

        [:> cmm/assets-context-menu*
         {:on-close on-close-menu
          :state @menu-state
          :options (cond-> [{:name    (tr "workspace.assets.rename")
                             :id      "assets-rename-group"
                             :handler #(on-rename % path last-path)}
                            {:name    (tr "workspace.assets.ungroup")
                             :id      "assets-ungroup-group"
                             :handler  #(on-ungroup path)}]
                     on-delete-group
                     (conj
                      {:name    (tr "workspace.assets.delete-group")
                       :id      "assets-delete-group"
                       :handler #(on-delete-group path)})

                     is-can-combine
                     (conj
                      {:name    (tr "workspace.shape.menu.combine-as-variants")
                       :id      "assets-combine-as-variants"
                       :handler  #(on-group-combine-variants path)}))}]]

       [:div {:class (stl/css :title-menu)}
        (when on-add
          [:> icon-button* {:variant "ghost"
                            :aria-label (tr "workspace.assets.typography.add-typography")
                            :on-click on-add
                            :icon i/add}])
        [:> icon-button* {:variant "ghost"
                          :aria-label (tr "workspace.assets.component-group-options")
                          :on-click on-context-menu
                          :icon i/menu}]]])))

(defn- sort-groups
  "Recursively sort subgroup keys alphabetically at every nesting level."
  [groups reverse-sort?]
  (let [cmp (if reverse-sort? #(compare %2 %1) compare)
        sort-tree (fn sort-tree [m]
                    (into (sorted-map-by cmp)
                          (map (fn [[k v]]
                                 [k (if (map? v) (sort-tree v) v)]))
                          m))]
    (sort-tree groups)))

(defn group-assets
  "Convert a list of assets in a nested structure like this:

    {'': [assetA assetB]
     'group1': {'': [asset1A asset1B]
                'subgroup11': {'': [asset11A asset11B asset11C]}
                'subgroup12': {'': [asset12A]}}
     'group2': {'subgroup21': {'': [asset21A]}}}
  "
  [assets reverse-sort?]
  (when-not (empty? assets)
    (-> (reduce (fn [groups {:keys [path] :as asset}]
                  (let [path (cpn/split-path (or path ""))]
                    (update-in groups
                               (conj path "")
                               (fn [group]
                                 (if group
                                   (conj group asset)
                                   [asset])))))
                {}
                assets)
        (sort-groups reverse-sort?))))

(def ^:private schema:group-form
  [:map {:title "GroupForm"}
   [:name [::sm/text {:max 250}]]])

(mf/defc name-group-dialog
  {::mf/register modal/components
   ::mf/register-as :name-group-dialog}
  [{:keys [path last-path accept] :as ctx
    :or {path "" last-path ""}}]
  (let [initial  (mf/with-memo [last-path]
                   {:asset-name last-path})
        form     (fm/use-form :schema schema:group-form
                              :initial initial)

        create?  (empty? path)

        on-accept
        (mf/use-fn
         (mf/deps form)
         (fn [_]
           (let [asset-name (get-in @form [:clean-data :name])]
             (if create?
               (accept asset-name)
               (accept path asset-name))
             (modal/hide!))))]

    [:div {:class (stl/css :modal-overlay)}
     [:div {:class (stl/css :modal-container)}
      [:div {:class (stl/css :modal-header)}
       [:h2  {:class (stl/css :modal-title)}
        (if create?
          (tr "workspace.assets.create-group")
          (tr "workspace.assets.rename-group"))]
       [:button {:class (stl/css :modal-close-btn)
                 :on-click modal/hide!} deprecated-icon/close]]

      [:div {:class (stl/css :modal-content)}
       [:& fm/form {:form form :on-submit on-accept}
        [:& fm/input {:name :name
                      :class (stl/css :input-wrapper)
                      :auto-focus? true
                      :label (tr "workspace.assets.group-name")
                      :hint (tr "workspace.assets.create-group-hint")}]]]

      [:div {:class (stl/css :modal-footer)}
       [:div {:class (stl/css :action-buttons)}
        [:input
         {:class (stl/css :cancel-button)
          :type "button"
          :value (tr "labels.cancel")
          :on-click modal/hide!}]

        [:input
         {:type "button"
          :class (stl/css-case :accept-btn true
                               :global/disabled (not (:valid @form)))
          :disabled (not (:valid @form))
          :value (if create? (tr "labels.create") (tr "labels.rename"))
          :on-click on-accept}]]]]]))
