/**
 * Copyright (c) 2022 - present TinyVue Authors.
 * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd.
 *
 * Use of this source code is governed by an MIT-style license.
 *
 * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
 * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
 * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
 *
 */

import { debounce } from '@opentiny/utils'
import {
  created,
  handleDragEnd,
  handleDrop,
  handleDragOver,
  handleDragStart,
  handleContentClick,
  handleChildNodeExpand,
  handleCheckChange,
  handleExpandIconClick,
  handleExpandClick,
  handleContextMenu,
  handleClick,
  handleSelectChange,
  getNodeKey,
  watchIndeterminate,
  watchChecked,
  watchExpanded,
  closeMenu,
  openEdit,
  addNode,
  saveEdit,
  deleteNode,
  onSiblingToggleExpand,
  watchExpandedChange,
  // tiny 新增
  computedExpandIcon,
  computedIndent
} from './index'

export const api = [
  'state',
  'getNodeKey',
  'handleClick',
  'handleContentClick',
  'closeMenu',
  'handleDragEnd',
  'handleDrop',
  'handleDragOver',
  'handleDragStart',
  'handleChildNodeExpand',
  'handleSelectChange',
  'handleContextMenu',
  'handleExpandIconClick',
  'openEdit',
  'addNode',
  'saveEdit',
  'deleteNode',
  'handleCheckChange'
]

const initState = ({ reactive, treeRoot, props, emitter, $parentEmitter, vm, api, TreeAdapter, computed }) => {
  const state = reactive({
    tree: treeRoot,
    expanded: false,
    oldChecked: null,
    indeterminate: null,
    oldIndeterminate: null,
    expandIcon: props.expandIcon,
    childNodeRendered: false,
    showMenu: false,
    menuposition: { position: 'absolute', top: 0, left: 0 },
    shrinkIcon: props.shrinkIcon,
    expandIconColor: props.expandIconColor,
    shrinkIconColor: props.shrinkIconColor,
    emitter: emitter(),
    parentEmitter: $parentEmitter,
    isSaaSTheme: (props.theme || vm.theme) === 'saas',
    props: treeRoot.props,
    renderedChildNodes: computed(() => {
      return props.node.childNodes.filter((childNode) => (TreeAdapter ? TreeAdapter.shouldRender(childNode) : true))
    }),
    computedExpandIcon: computed(() => api.computedExpandIcon(treeRoot, state)),
    computedIndent: computed(() => api.computedIndent(props, state))
  })

  return state
}

const initApi = ({ api, state, dispatch, broadcast, vm, props, treeRoot, nextTick, emit, designConfig }) => {
  Object.assign(api, {
    state,
    dispatch,
    broadcast,
    watchExpanded: debounce(20, watchExpanded({ state })),
    created: created({ props, state }),
    getNodeKey: getNodeKey(state),
    closeMenu: closeMenu(state),
    handleSelectChange: handleSelectChange({ props, state }),
    handleContextMenu: handleContextMenu({ vm, treeRoot, props, state, nextTick }),
    handleExpandClick: handleExpandClick({ emit, vm, props, state }),
    handleCheckChange: handleCheckChange({ nextTick, props, state }),
    handleDragStart: handleDragStart({ state, vm }),
    handleDragOver: handleDragOver({ state, vm }),
    handleDrop: handleDrop(),
    handleDragEnd: handleDragEnd({ state, vm }),
    handleContentClick: handleContentClick({ nextTick, props, state, emit }),
    onSiblingToggleExpand: onSiblingToggleExpand({ state, props }),
    watchExpandedChange: watchExpandedChange({ state, props }),
    handleClick: handleClick({ api, vm, props, state }),
    watchIndeterminate: watchIndeterminate({ api, props }),
    watchChecked: watchChecked({ api, props }),
    openEdit: openEdit({ state, vm }),
    addNode: debounce(500, true, addNode({ state, props, api })),
    saveEdit: saveEdit({ state }),
    deleteNode: deleteNode({ state }),
    handleChildNodeExpand: handleChildNodeExpand(state),
    handleExpandIconClick: handleExpandIconClick({ api, state }),
    computedExpandIcon: computedExpandIcon({ designConfig }),
    computedIndent: computedIndent()
  })
}

const initWatcher = ({ watch, state, api, props }) => {
  watch(() => state.expanded, api.watchExpandedChange)

  watch(() => props.node.indeterminate, api.watchIndeterminate, { deep: true })

  watch(() => props.node.checked, api.watchChecked, { deep: true })

  watch(() => props.node.expanded, api.watchExpanded, { deep: true })
}

export const renderless = (
  props,
  { reactive, watch, inject, provide, computed },
  { vm, nextTick, emit, broadcast, dispatch, emitter, designConfig },
  { isVue2 }
) => {
  const api = {}
  const treeRoot = inject('TreeRoot')
  const $parentEmitter = inject('parentEmitter')
  const TreeAdapter = inject('TreeAdapter', null)
  const state = initState({ reactive, treeRoot, props, emitter, $parentEmitter, vm, api, TreeAdapter, computed })

  if (state.tree.accordion) {
    state.parentEmitter.on('sibling-node-toggle-expand', (event) => api.onSiblingToggleExpand(event))
  }

  provide('parentEmitter', state.emitter)

  initApi({ api, state, dispatch, broadcast, vm, props, treeRoot, nextTick, emit, designConfig })
  initWatcher({ watch, state, api, props })

  api.created((childrenKey) => {
    watch(
      () => props.node.data[childrenKey],
      () => {
        props.node.updateChildren()
      }
    )

    if (!isVue2) {
      props.node.updateMethod = (node, field) => {
        field === 'expanded' && api.watchExpanded(node[field])
      }
    }
  })

  state.parentEmitter.on('closeMenu', () => {
    api.closeMenu()
    state.emitter.emit('closeMenu')
  })

  return api
}