import { deepCopy, deepObjectMerge, IActionParam, IParam, isEmpty, isExistAndNotEmpty, MDControl, UIUtil } from "@core";
import { TreeControlProps } from "./tree-control-prop";
import { TreeControlState } from "./tree-control-state";

/**
 * @description 树部件
 * @export
 * @class TreeControl
 * @extends {MainControl}
 */
export class TreeControl extends MDControl {
  /**
   * @description 部件状态
   * @type {TreeControlState}
   * @memberof TreeControl
   */
  public declare state: TreeControlState;

  /**
   * @description 根据props调整设置部件state
   * @memberof TreeControl
   */
  public setState(): void {
    super.setState();
    this.state.isBranchAvailable = toRef(this.props, 'isBranchAvailable') !== false;
  }

  /**
   * @description 处理选中数据
   * @protected
   * @param {IParam[]} newVal
   * @param {*} oldVal
   * @memberof TreeControl
   */
  protected handleSelectedData(newVal: IParam[], oldVal: any) {
    const { selectedKeys, selectedNodes } = toRefs(this.state);
    const keys: string[] = [];
    const nodes: IParam[] = [];
    newVal.forEach((value: IParam) => {
      if (value.srfkey) {
        const node = this.getTreeNodeByKey(value.srfkey, 'srfkey');
        if (node) {
          keys.push(node.id);
          nodes.push(node);
        }
      }
    });
    selectedKeys.value = [...keys];
    selectedNodes.value = [...nodes];
  }

  /**
   * @description 树节点选中
   * @param {string} nodeId
   * @param { nativeEvent: MouseEvent, node: any, selected: boolean } e
   * @memberof TreeControl
   */
  protected onTreeNodeSelect(nodeId: string, e: { nativeEvent: MouseEvent, node: any, selected: boolean }) {
    if (e.node.disabled) {
      e.node.isCurrent = false;
      return;
    }
    const { isBranchAvailable, isMultiple } = this.state;
    const { selectedNodes, currentSelectedNode } = toRefs(this.state);
    if (isBranchAvailable || e.node.isLeaf) {
      if (currentSelectedNode.value && Object.keys(currentSelectedNode.value).length > 0) {
        currentSelectedNode.value.srfchecked = 0;
      }
      e.node.srfchecked = 1;
      currentSelectedNode.value = e.node;
      if (!isMultiple) {
        selectedNodes.value = [currentSelectedNode.value];
      } else {
        selectedNodes.value.push(e.node);
      }
      this.emit("ctrlEvent", { tag: this.props.name, action: 'selectionChange', data: deepCopy(selectedNodes.value) });
    }
  }

  /**
   * 树节点复选框选中
   *
   * @protected
   * @param {string[]} _checkedKeys
   * @param {{ nativeEvent: MouseEvent, node: IParam, checkedNodes: IParam[] }} { nativeEvent: event, node, checkedNodes  }
   * @memberof TreeControl
   */
  protected onCheck(_checkedKeys: string[], { nativeEvent: event, node, checkedNodes  }: { nativeEvent: MouseEvent, node: IParam, checkedNodes: IParam[] }) {
    const { selectedNodes } = toRefs(this.state);
    if (this.state.isMultiple) {
      selectedNodes.value = [...checkedNodes];
      this.emit("ctrlEvent", { tag: this.props.name, action: "selectionChange", data: selectedNodes.value });
    }
  }

  /**
   * @description 计算节点上下文
   * @private
   * @param {*} curNode
   * @return {*} 
   * @memberof TreeControl
   */
  private computecurNodeContext(curNode: any) {
    const { context } = this.state;
    let tempContext: any = {};
    if (curNode && curNode.srfappctx) {
      tempContext = deepCopy(curNode.srfappctx);
    } else {
      tempContext = deepCopy(context);
    }
    return tempContext;
  }

  /**
   * @description 加载数据
   * @protected
   * @param {*} node 树节点
   * @param {boolean} [isFirst]
   * @return {*}  {Promise<any>}
   * @memberof TreeControl
   */
  protected async load(node: any, isFirst?: boolean): Promise<any> { }

  /**
   * @description 使用加载功能模块
   * @return {*}
   * @memberof TreeControl
   */
  public useLoad() {
    const { viewSubject, controlName } = this.state;
    const load = async (node?: any, isFirst: boolean = false): Promise<any> => {
      if (node?.children && node.children.length) {
        return null;
      }
      const {
        controlService, viewParams, srfnodefilter
      } = this.state;
      let tempViewParams: any = deepCopy(viewParams);
      let curNode: any = {};
      curNode = deepObjectMerge(curNode, node);
      const params: any = {
        srfnodeid: node && node.id ? node.id : '#',
        srfnodefilter: srfnodefilter,
        parentData: curNode?.curData
      }
      let tempContext: any = this.computecurNodeContext(curNode);
      if (curNode && curNode.sefparentdename) {
        Object.assign(tempContext, { srfparentdename: curNode.srfparentdename });
        Object.assign(tempViewParams, { srfparentdename: curNode.srfparentdename });
      }
      if (curNode && curNode.srfparentdemapname) {
        Object.assign(tempContext, { srfparentdemapname: curNode.srfparentdemapname });
        Object.assign(tempViewParams, { srfparentdemapname: curNode.srfparentdemapname });
      }
      if (curNode && curNode.srfparentkey) {
        Object.assign(tempContext, { srfparentkey: curNode.srfparentkey });
        Object.assign(tempViewParams, { srfparentkey: curNode.srfparentkey });
      }
      Object.assign(params, { viewParams: tempViewParams });
      try {
        const response = await controlService.getNodes(tempContext, params);
        if (!response || response.status !== 200) {
          return null;
        }
        const data = response.data;
        this.formatExpanded(data);
        this.formatAppendCaption(data);
        const isRoot = !node || !node.parent;
        const { items } = toRefs(this.state);
        if (isFirst) {
          items.value.splice(0, items.value.length);
          data.forEach((item: any) => {
            items.value.push(item);
          });
        } else {
          const nodeData = this.getTreeNodeByKey(node.id);
          data.forEach((item: any) => {
            item.parentNodeId = node.id;
          });
          if (nodeData) {
            nodeData.children = data;
          }
        }
        const isSelectedAll = node?.checked;
        this.setDefaultSelection(data, isRoot, isSelectedAll);
        this.emit("ctrlEvent", { tag: this.props.name, action: "load", data: data });
      } catch (error) {
        console.error(error);
      }
    }

    // 在类里绑定能力方法
    this.load = load;

    // 订阅viewSubject,监听load行为
    if (viewSubject) {
      let subscription = viewSubject.subscribe(({ tag, action, data }: IActionParam) => {
        if (!Object.is(controlName, tag)) {
          return;
        }
        if (Object.is("load", action)) {
          load(data, true);
        }
      })
      // 部件卸载时退订viewSubject
      onUnmounted(() => {
        subscription.unsubscribe();
      })
    }
    return load;
  }

  /**
   * 使用搜索模块
   *
   * @memberof TreeControl
   */
  public useSearch() {
    const { viewSubject, controlName } = this.state;
    // 订阅viewSubject,监听search行为
    if (viewSubject) {
      let subscription = viewSubject.subscribe(({ tag, action, data }: IActionParam) => {
        if (!Object.is(controlName, tag)) {
          return;
        }
        if (Object.is("search", action)) {
          this.state.srfnodefilter = data?.query;
          this.load({}, true);
        }
      })
      // 部件卸载时退订viewSubject
      onUnmounted(() => {
        subscription.unsubscribe();
      })
    }
  }

  /**
   * 使用刷新模块
   *
   * @return {*} 
   * @memberof TreeControl
   */
  public useRefresh() {
    const { viewSubject, controlName } = this.state;

    /**
     * 刷新行为
     *
     * @param [opt={}]
     * @return {*}
     */
    const refresh = async (opt: any = {}) => {
      if (opt && opt.target) {
        if (opt.target === 'parent') {
          this.refreshParent();
        } else if (opt.target === 'all') {
          this.refreshAll();
        }
      } else {
        this.load(opt);
      }
    };

    // 在类里绑定能力方法
    this.refresh = refresh;

    // 订阅viewSubject,监听load行为
    if (viewSubject) {
      let subscription = viewSubject.subscribe(({ tag, action, data }: IActionParam) => {
        if (Object.is(controlName, tag) && Object.is('refresh', action)) {
          refresh(data);
        }
      });

      // 部件卸载时退订viewSubject
      onUnmounted(() => {
        subscription.unsubscribe();
      });
    }
    return refresh;
  }

  /**
   * 刷新父节点
   *
   * @protected
   * @memberof TreeControl
   */
  protected refreshParent() {
    const { currentSelectedNode } = this.state;
    if (currentSelectedNode && currentSelectedNode.parentNodeId) {
      //  父节点
      const parentNode = this.getTreeNodeByKey(currentSelectedNode.parentNodeId);
      if (parentNode) {
        delete parentNode.children;
        // this.load(parentNode);
      }
    }
  }

  /**
   * 刷新全部节点
   *
   * @protected
   * @memberof TreeControl
   */
  protected refreshAll() {
    const { currentSelectedNode } = this.state;
    // this.load({}, true);
  }

  /**
   * @description 设置默认展开节点
   * @protected
   * @param {IParam[]} items
   * @memberof TreeControl
   */
  protected formatExpanded(items: IParam[]) {
    const { expandedKeys } = this.state;
    items.forEach((item: any) => {
      if (item.expanded && expandedKeys.findIndex((key: string) => key === item.id) === -1) {
        expandedKeys.push(item.id);
      }
    })
  }

  /**
   * @description 设置附加标题栏
   * @protected
   * @param {IParam[]} items
   * @memberof TreeControl
   */
  protected formatAppendCaption(items: IParam[]) {
    items.forEach(item => {
      if (item.appendCaption && item.textFormat) {
        item.text = item.textFormat + item.text;
      }
    });
  }

  /**
   * @description 设置默认选中
   * @protected
   * @param {IParam[]} items 节点数据
   * @param {boolean} [isRoot=false] 是否是根节点
   * @param {boolean} [isSelectedAll=false] 是否选中全部
   * @return {*}  {void}
   * @memberof TreeControl
   */
  protected setDefaultSelection(items: IParam[], isRoot: boolean = false, isSelectedAll: boolean = false): void {
    if (items.length === 0) {
      return;
    }
    const {
      selectFirstDefault,
      isMultiple,
      viewParams,
      currentSelectedNode,
      isBranchAvailable
    } = this.state;
    let { selectedNodes, echoSelectedNodes, selectedKeys } = this.state;
    let defaultData: any;
    //  导航视图中，有选中数据时选中该数据，无选中数据默认选中第一项
    if (selectFirstDefault) {
      //  单选
      if (!isMultiple) {
        let index: number = -1;
        if (selectedNodes && selectedNodes.length > 0) {
          //  单选时选中节点数组只有一项
          const selectedNode: IParam = selectedNodes[0];
          index = items.findIndex((item: IParam) => {
            if (isEmpty(item.srfkey)) {
              return selectedNode.id == item.id;
            } else {
              return selectedNode.srfkey == item.srfkey;
            }
          });
        }
        if (index === -1) {
          if (isRoot) {
            if (viewParams && viewParams.srfnavtag) {
              const activate = viewParams.srfnavtag;
              index = items.findIndex((item: any) => {
                return item.id && item.id.split(';') && (item.id.split(';')[0] == activate);
              });
              if (index === -1) index = 0;
            } else {
              index = 0;
            }
          } else {
            return;
          }
        }
        defaultData = items[index];
        // 置空选中节点标识集合，避免破坏响应式
        selectedKeys.splice(0, selectedKeys.length);
        selectedKeys.push(defaultData.id);
        currentSelectedNode.value = deepCopy(defaultData);
        if (isBranchAvailable || defaultData.isLeaf) {
          selectedNodes.splice(0, selectedNodes.length);
          selectedNodes.push(currentSelectedNode.value);
          this.emit("ctrlEvent", { tag: this.props.name, action: "selectionChange", data: selectedNodes });
        }
      }
    }
    //  默认选中
    const defualtSelect = items.find((item: any) => item.selected);
    if (defualtSelect) {
      if (isMultiple && selectedNodes.findIndex((node: any) => node.id === defualtSelect.id) === -1) {
        selectedNodes.push(deepCopy(defualtSelect));
        //  设置选中样式
        selectedKeys.push(defualtSelect.id);
      } else if (!isMultiple) {
        selectedNodes.splice(0, selectedNodes.length);
        currentSelectedNode.value = deepCopy(defualtSelect);
        selectedNodes.push(currentSelectedNode.value);
        //  设置选中样式
        selectedKeys.splice(0, selectedKeys.length);
        selectedKeys.push(defualtSelect.id);
      }
      this.emit("ctrlEvent", { tag: this.props.name, action: "selectionChange", data: selectedNodes });
    }
    //  回显已选数据
    if (echoSelectedNodes && echoSelectedNodes.length > 0) {
      const checkedNodes = items.filter((item: IParam) => {
        return echoSelectedNodes.some((val: IParam) => {
          if (Object.is(item.srfkey, val.srfkey) && Object.is(item.srfmajortext, val.srfmajortext)) {
            val.used = true;
            selectedNodes.push(val);
            selectedKeys.push(val.id);
            this.emit("ctrlEvent", { tag: this.props.name, action: "selectionChange", data: selectedNodes });
            return true;
          }
        })
      });
      if (checkedNodes.length) {
        // TODO 待确认响应式是否会消失
        echoSelectedNodes = echoSelectedNodes.filter((item: any) => !item.used);
        if (!isSelectedAll) {
          if (isMultiple) {
            checkedNodes.push((node: any) => {
              selectedNodes.push(node);
              selectedKeys.push(node.id);
            });
          } else {
            //  TODO 设置选中树节点高亮
            currentSelectedNode.value = deepCopy(checkedNodes[0]);
            selectedNodes.splice(0, selectedNodes.length);
            selectedNodes.push(currentSelectedNode.value);
            //  设置选中样式
            selectedKeys.splice(0, selectedKeys.length);
            selectedKeys.push(currentSelectedNode.value.id);
          }
        }
      }
    }
    //  父节点选中树，选中所有子节点
    if (isSelectedAll) {
      const leafNodes = items.filter((item: any) => item.isLeaf);
      leafNodes.forEach((node: any) => {
        selectedNodes.push(node);
        selectedKeys.push(node.id);
      });
      this.emit("ctrlEvent", { tag: this.props.name, action: 'selectionChange', data: selectedNodes });
    }
  }

  /**
   * @description 树节点上下文菜单点击
   *
   * @protected
   * @param {*} node 节点
   * @param {*} { key, domEvent: event } key：行为标识，event：鼠标源事件
   * @return {*} 
   * @memberof TreeControl
   */
  protected onContextMenuClick(node: any, { key, domEvent: event }: any) {
    const { context, viewParams, contextMenus } = this.state;
    const action = contextMenus[node.nodeType]?.find((item: IParam) => item.name === key);
    this.state.currentSelectedNode = node;
    if (!action) {
      console.warn("上下文菜单执行参数不足");
      return;
    }
    const inputParam = {
      context: context,
      viewParams: viewParams,
      data: [node.curData],
      event: event,
      actionEnvironment: this
    };
    App.getAppActionService().execute(action, inputParam);
  }

  /**
   * @description 树节点右键点击
   * @protected
   * @param {*} { event, node }
   * @memberof TreeControl
   */
  protected onRightClick({ event, node }: any) {
    //  计算节点上下文菜单权限
    this.computeNodeContextMenuState(node, event);
  }

  /**
   * @description 计算节点上下文菜单权限
   * @private
   * @param {*} node
   * @param {MouseEvent} event
   * @memberof TreeControl
   */
  private computeNodeContextMenuState(node: any, event: MouseEvent) {
    const { contextMenus, UIService } = this.state;
    if (contextMenus && contextMenus[node.nodeType]) {
      UIUtil.calcActionItemAuthState(node, contextMenus[node.nodeType], UIService);
    }
  }

  /**
   * @description 根据节点标识获取父节点
   * @private
   * @param {string} id 节点标识
   * @return {*} 
   * @memberof TreeControl
   */
  private getTreeNodeByKey(id: string, key: string = 'id'): any {
    const { items } = toRefs(this.state);
    if (!isExistAndNotEmpty(id) || (!items.value || items.value.length === 0)) {
      return null;
    }
    let node: any = null;
    const getNode = (item: any): boolean => {
      let flag: boolean = false;
      if (item[key] === id) {
        node = item;
        flag = true;
      }
      if (item.children && item.children.length > 0) {
        for (const child of item.children) {
          if (getNode(child)) {
            flag = true;
            break;
          }
        }
      }
      return flag;
    }
    for (const item of items.value) {
      if (getNode(item)) {
        break;
      }
    }
    return node;
  }

  /**
   * @description 安装部件所有功能模块的方法
   * @return {*}
   * @memberof TreeControl
   */
  public moduleInstall() {
    const superParams = super.moduleInstall();
    this.useSearch();
    return {
      ...superParams,
      onTreeNodeSelect: this.onTreeNodeSelect.bind(this),
      onContextMenuClick: this.onContextMenuClick.bind(this),
      onRightClick: this.onRightClick.bind(this),
      onCheck: this.onCheck.bind(this)
    };
  }
}