(ns mini-program-cljs.clj-core
  (:require
   [mini-program-cljs.uuid :as uuid]
   [clojure.walk :as walk]))

(defn clj-flatten [^js js-array]
  (clj->js (flatten (js->clj js-array))))


(comment
  (postwalk-tree-op  tree-data
    (fn [hash]
      (prn "-----" hash))))
(defn postwalk-tree-op
  "hash树的操作"
  [^js tree-data hash-ob]
  (clj->js
    (walk/postwalk
      (fn [x]
        (cond
          (map? x)
          , x
          (and (vector? x)
            (= (count x) 2)
            (map? (first x)))
          , (hash-ob x)
          :else x))
      (js->clj tree-data))))

(defn insert-nav->tree
  "插入节点到树里面"
  [^js tree-data pid content hulunote-note]
  (let [data {:content content
              :parid pid
              :hulunoteNote hulunote-note}
        deep-atom (atom 0)
        new-id (uuid/v1)]
    (postwalk-tree-op
      tree-data
      (fn [x]
        (cond
          ;; 通过找到pid的id数据位置,插入到它的下面
          (= (get (first x) "id") pid)
          , (let [deep (inc (get (first x) "deep"))]
              (js/console.log "插入新的数据到树, " "父ID: " pid ", 数据:" data
                ", 深度: " deep "##" (first x))
              (reset! deep-atom deep)
              [(first x) [(last x)
                          [(merge
                             {:id new-id :deep deep}
                             data) []]]])
          :else x)))))

(defn filter-tree-as-list
  "展示树的局部: 切割树"
  [^js tree-data fdeep hulunote-nav parid]
  (let [splits (->>
                 (js->clj tree-data)
                 (flatten)
                 (filter
                   (fn [item]
                     (>= (get item "deep") fdeep)))
                 (split-with
                   (complement #(= hulunote-nav (get  % "id")))))
        res (last splits)]
    (prn "====切割的前部分:" (first  splits))
    (clj->js
      (concat [(first res)]
        (first
          (split-with
            (complement #(= parid (get % "parid")))
            (rest res)))))))

(defn update-nav-data
  "更新树nav内容"
  [^js tree-data ^js params hulunote-nav]
  (let [op-fn (fn [nav]
                (if (= (get nav "id") hulunote-nav)
                  (merge nav (js->clj params))
                  nav))
        new-tree (clojure.walk/postwalk
                   (fn [x]
                     (if (map? x)
                       (op-fn x)
                       x))
                   (js->clj tree-data))]
    (clj->js new-tree)))

(defn enter-event-insert-flatlist
  "回车之后添加新行的input的函数: 解决视觉内最近的增加行"
  [^js flist enter-id uuid content
   hulunote-note sub-deep-fn deep-fn]
  (let [flatlist (js->clj flist)
        num (first
              (keep-indexed
                #(if (= (get %2 "id") enter-id) %1)
                flatlist))
        current (nth flatlist num)
        _ (prn "当前enter的节点:" current)
        ;; ------
        ;; 列表的前一部分和后一部分
        before-list (take num flatlist)
        after-list (drop  (+ num 1)  flatlist)
        ;; 当前enter的nav的相邻的前后flat节点
        before (last before-list)
        after (first  after-list)
        _ (prn "前一个节点:" before ", 后一个节点: " after)
        ;; 如果当前的深度等于下一层深度,那么插入的deep就等于当前回车的编辑的深度,否则就是下一个的深度
        new-deep (cond (= (get current "deep")
                         (get after "deep"))
                       , (get current "deep")
                       ;; 如果下一级深度小于当前enter nav的深度: 就采用当前enter的深度
                       (> (get current "deep")
                         (get after "deep"))
                       , (get current "deep")
                       :else
                       (get after "deep"))
        ;; 如果当前的深度等于下一层深度,那么插入的parid就等于当前回车的编辑的parid,否则就是下一个的parid => 只要复用就不复杂了,一层层往上复用抽象表达 # 用的高阶函数dsl来表示
        new-parid (cond (= (get current "deep")
                          (get after "deep"))
                        , (get current "parid")
                        (> (get current "deep")
                          (get after "deep"))
                        , (get current "parid")
                        :else
                        (get current "id"))
        ;; --------
        new-data {:id uuid
                  :content content
                  :hulunote-note hulunote-note
                  :deep (deep-fn new-deep)
                  :deepRange (range (sub-deep-fn new-deep)) ;; 给对外更多的可编程接口: 可编程函数(高阶函数)
                  #_(if (int? sub-deep)
                      (range
                        (- (- new-deep 1)
                          (- sub-deep 1)))
                      (range (- new-deep 1)) ;; 最后输出还要减一: 显示竖直分割线 # 显示
                      )
                  :parid new-parid}]
    (prn "新的nav: " new-data)
    (clj->js
      {:newFlattenList (concat before-list [current new-data] after-list)
       :newNav new-data})))
