import LogicFlow from '@logicflow/core';
import { DndPanel, Control, Menu, MiniMap, Snapshot } from '@logicflow/extension';
import StartSvg from '../assets/images/panel-start.svg';
import EndSvg from '../assets/images/panel-end.svg';
import TaskSvg from '../assets/images/panel-task.svg';
import DecisionSvg from '../assets/images/panel-decision.svg';
import CustomSvg from '../assets/images/panel-custom.svg';
import ForkSvg from '../assets/images/panel-fork.svg';
import JoinSvg from '../assets/images/panel-join.svg';
import SubProcessSvg from '../assets/images/panel-subprocess.svg';

LogicFlow.use(DndPanel)
LogicFlow.use(Control)
LogicFlow.use(Menu)
LogicFlow.use(MiniMap, {
  width: 200,
  height: 150,
  showEdge: true,
  isShowHeader: false,
  isShowCloseIcon: true,
})
LogicFlow.use(Snapshot)

const nodes = import.meta.glob('../nodes/*.ts',{
  eager: true
})
const edges = import.meta.glob('../edges/*.ts',{
  eager: true
})

class Flow {
  dndPanel: any[] = []
  miniMapVisible: boolean = false
  static pluginName = 'flow'
  static defaultEdgeType = 'transition'
  defaultDndPanel: any[] = [
    {
      type: 'start',
      text: '开始',
      icon: StartSvg,
      className: 'dnd-start',
      sort: 10
    },
    {
      type: 'task',
      text: '用户任务',
      icon: TaskSvg,
      className: 'dnd-task',
      sort: 20
    },
    {
      type: 'decision',
      text: '条件判断',
      icon: DecisionSvg,
      className: 'dnd-decision',
      sort: 30
    },
    {
      type: 'fork',
      text: '分支',
      icon: ForkSvg,
      className: 'dnd-fork',
      sort: 40
    },
    {
      type: 'join',
      text: '合并',
      icon: JoinSvg,
      className: 'dnd-join',
      sort: 50
    },
    {
      type: 'subProcess',
      text: '子流程',
      icon: SubProcessSvg,
      className: 'dnd-subprocess',
      sort: 60
    },
    {
      type: 'custom',
      text: '自定义',
      icon: CustomSvg,
      className: 'dnd-custom',
      sort: 70
    },
    {
      type: 'end',
      text: '结束',
      icon: EndSvg,
      className: 'dnd-end',
      sort: 80
    }
  ]
  props: any;
  defaultControl: any[] = [
    {
      key: 'zoom-out',
      iconClass: 'lf-control-zoomOut',
      title: '缩小流程图',
      text: '缩小',
      sort: 10,
      onClick: () => {
        this.lf.zoom(false);
      },
    },
    {
      key: 'zoom-in',
      iconClass: 'lf-control-zoomIn',
      title: '放大流程图',
      sort: 20,
      text: '放大',
      onClick: () => {
        this.lf.zoom(true);
      },
    },
    {
      key: 'reset',
      iconClass: 'lf-control-fit',
      title: '恢复流程原有尺寸',
      text: '适应',
      sort: 30,
      onClick: () => {
        this.lf.resetZoom();
      },
    },
    {
      key: 'undo',
      iconClass: 'lf-control-undo',
      title: '回到上一步',
      text: '上一步',
      sort: 40,
      onClick: () => {
        this.lf.undo();
      },
    },
    {
      key: 'redo',
      iconClass: 'lf-control-redo',
      title: '移到下一步',
      sort: 50,
      text: '下一步',
      onClick: () => {
        this.lf.redo();
      },
    },
    {
      key: 'clear',
      iconClass: 'lf-control-clear',
      title: '清空画布',
      sort: 60,
      text: '清空',
      onClick: () => {
        this.lf.clearData();
      }
    },
    {
      key: 'see',
      iconClass: 'lf-control-see',
      title: '查看流程数据',
      sort: 70,
      text: '查看',
      onClick: () => {
        this.props.modalRef?.value?.show({
          type: 'see',
          graphData: this.lf.getGraphData(),
          lf: this.lf
        })
      }
    },
    {
      key: 'import',
      iconClass: 'lf-control-import',
      title: '导入流程数据',
      sort: 80,
      text: '导入',
      onClick: () => {
        this.props.modalRef?.value?.show({
          type: 'import',
          lf: this.lf
        })
      }
    },
    {
      key: 'highlight',
      iconClass: 'lf-control-highlight',
      title: '设置高亮数据',
      sort: 85,
      text: '高亮',
      onClick: () => {
        this.props.modalRef?.value?.show({
          type: 'highlight',
          lf: this.lf
        })
      }
    },
    {
      key: 'save',
      iconClass: 'lf-control-save',
      title: '保存流程数据',
      sort: 90,
      text: '保存',
      onClick: () => {
        const { eventCenter } = this.lf.graphModel;
        eventCenter.emit("custom:save", this.lf.getGraphData());
      }
    },
    {
      key: 'minimap',
      iconClass: 'lf-control-minimap',
      title: '切换小地图',
      sort: 100,
      text: '小地图',
      onClick: () => {
        const miniMap = this.lf.extension.miniMap
        if (miniMap) {
          if (this.miniMapVisible) {
            miniMap.hide()
            this.miniMapVisible = false
          } else {
            miniMap.show()
            miniMap.updatePosition({ right: 15, top: 70 })
            this.miniMapVisible = true
          }
        }
      }
    }
  ]
  lf: any;
  constructor(data: any){
    this.lf = data.lf;
    const props = data.props
    this.props = props
    
    // 注册节点和边，并添加类型前缀
    Object.keys(nodes).forEach((key) => {
      const node = (nodes[key] as any).default
      if (node && node.type) {
        if (props.typePrefix && !node.type.startsWith(props.typePrefix)) {
          node.type = `${props.typePrefix}${node.type}`
        }
        this.lf.register(node)
        console.log(`Registered node: ${node.type}`)
      } else {
        console.warn(`Node ${key} is invalid:`, node)
      }
    })
    Object.keys(edges).forEach((key) => {
      const edge = (edges[key] as any).default
      if (edge && edge.type) {
        if (props.typePrefix && !edge.type.startsWith(props.typePrefix)) {
          edge.type = `${props.typePrefix}${edge.type}`
        }
        this.lf.register(edge)
      } else {
        console.warn(`Edge ${key} is invalid:`, edge)
      }
    })

    // 设置默认边类型
    let defaultEdgeType = props.defaultEdgeType || Flow.defaultEdgeType
    if (props.typePrefix && !defaultEdgeType.startsWith(props.typePrefix)) {
      defaultEdgeType = `${props.typePrefix}${defaultEdgeType}`
    }
    this.lf.setDefaultEdgeType(defaultEdgeType)

    // 初始化拖拽面板
    if (props.initDndPanel !== false && props.viewer !== true) {
      // 拖拽面板追加类型前辍
      const defaultDndPanelWithPrefix = this.defaultDndPanel.map((item: any) => {
        if (props.typePrefix && item.type && !item.type.startsWith(props.typePrefix)) {
          return {
            ...item,
            type: `${props.typePrefix}${item.type}`
          }
        }
        return item
      })
      
      const newDndPanel: any[] = [...defaultDndPanelWithPrefix]
      if(props.dndPanel && props.dndPanel.length > 0) {
        props.dndPanel.forEach((item: any) => {
          const index = newDndPanel.findIndex((i) => i.type === item.type)
          if(index > -1) {
            if(item.hide === true) {
              newDndPanel.splice(index, 1)
            } else {
              newDndPanel[index] = {
                ...newDndPanel[index],
                ...item,
              }
            }
          } else {
            newDndPanel.push(item)
          }
        })
      }
      newDndPanel.sort((a: any, b: any) => {
        return (a.sort === undefined ? 99: a.sort) - (b.sort === undefined ? 99: b.sort)
      })
      this.initDndPanel(newDndPanel)
    }

    // 初始化控制面板
    if (props.initControl !== false) {
      const newControl: any[] = [...this.defaultControl]
      if(props.control && props.control.length > 0) {
        props.control.forEach((item: any) => {
          const index = newControl.findIndex((i) => i.key === item.key)
          if(index > -1) {
            if(item.hide === true) {
              newControl.splice(index, 1)
            } else {
              newControl[index] = {
                ...newControl[index],
                ...item,
              }
            }
          } else {
            newControl.push(item)
          }
        })
      }
      newControl.sort((a: any, b: any) => {
        return (a.sort === undefined ? 99: a.sort) - (b.sort === undefined ? 99: b.sort)
      })
      this.initControl(newControl.filter(item=>{
        if(props.viewer === true) {
          return !['undo','redo','clear','save','see','import','highlight'].includes(item.key)
        }
        return true
      }))
    } else {
      this.lf.extension.control.controlItems = []
    }

    if(props.viewer) {
      this.lf.extension.menu.setMenuConfig({})
    } else {
      this.lf.on('blank:contextmenu', (e: any) => {
        if (e.preventDefault) {
          e.preventDefault();
        }
        
        // 优先调用用户传入的blankContextmenu方法
        if (props.blankContextmenu && typeof props.blankContextmenu === 'function') {
          const processData: any = {};
          const flowFields = ['name', 'display_name', 'key', 'version', 'expire_time', 'instance_url', 'instance_no_class', 'pre_interceptors', 'post_interceptors', 'formType', 'customFormConfig'];
          flowFields.forEach(field => {
            if (this.lf.graphModel[field] !== undefined) {
              processData[field] = this.lf.graphModel[field];
            }
          });
          
          // 调用用户传入的blankContextmenu方法
          props.blankContextmenu({
            data: {
              type: 'process',
              lf: this.lf,
              properties: processData
            }
          });
        } else {
          // 如果用户没有传入blankContextmenu方法，检查dndPanel中是否有type为'process'的配置
          const processData: any = {};
          const flowFields = ['name', 'display_name', 'key', 'version', 'expire_time', 'instance_url', 'instance_no_class', 'pre_interceptors', 'post_interceptors', 'formType', 'customFormConfig'];
          flowFields.forEach(field => {
            if (this.lf.graphModel[field] !== undefined) {
              processData[field] = this.lf.graphModel[field];
            }
          });

          // 检查dndPanel中是否有type为'process'的配置
          const dndPanel = props.dndPanel;
          const processConfig = dndPanel?.find((item: any) => item.type === 'process');
          if (processConfig) {
            // 调用process配置的nodeClick方法
            if (processConfig.nodeClick) {
              processConfig.nodeClick({
                data: {
                  type: 'process',
                  lf: this.lf,
                  properties: processData
                }
              });
            }
          } else if (this.props.drawerRef?.value?.show) {
            // 使用内置的流程设置面板
            this.props.drawerRef.value.show({
              type: 'process',
              lf: this.lf,
              properties: processData
            });
          }
        }
      });

      this.lf.extension.menu.setMenuConfig({
        nodeMenu: [
          {
            text: '删除',
            callback: (node: any) => {
              this.lf.deleteNode(node.id)
            }
          }
        ],
        graphMenu: []
      })
    }

    const lf = this.lf;

    lf.adapterIn = (userData: any) => {
      const flowFields = ['name', 'display_name', 'key', 'version', 'expire_time', 'instance_url', 'instance_no_class', 'pre_interceptors', 'post_interceptors', 'formType', 'customFormConfig'];
      flowFields.forEach(field => {
        if (userData[field] !== undefined) {
          lf.graphModel[field] = userData[field];
        }
      });
      return userData;
    };

    lf.adapterOut = (userData: any) => {
      const processData: any = {};
      const flowFields = ['name', 'display_name', 'key', 'version', 'expire_time', 'instance_url', 'instance_no_class', 'pre_interceptors', 'post_interceptors', 'formType', 'customFormConfig'];
      flowFields.forEach(field => {
        if (lf.graphModel[field] !== undefined) {
          processData[field] = lf.graphModel[field];
        }
      });
      return {
        ...userData,
        ...processData
      };
    };

    lf.graphModel.props = props;
    const { eventCenter } = lf.graphModel;
    eventCenter.on('node:click', (event: any) => {
      if(props.viewer === true) {
        return
      }
      const shapeList = this.dndPanel
      const index = shapeList.findIndex((item: any)=>item.type === event.data.type)
      let nodeClick = props.nodeClick
      if(index>=-1) {
        nodeClick = shapeList[index]?.nodeClick || props.nodeClick
      }
      if(nodeClick && typeof nodeClick === 'function') {
        nodeClick(event)
      } else {
        const nodeData = {
          id: event.data.id,
          type: event.data.type,
          label: event.data.text?.value || event.data.text || '',
          properties: {
            ...event.data.properties
          }
        };

        const nodeConfig = props.nodeConfig?.find((config: any) => config.type === event.data.type);
        let customPanel = props.customPanel;
        let useExternalPanel = false;

        if (nodeConfig) {
          if (nodeConfig.customPanel) {
            customPanel = nodeConfig.customPanel;
          }
        }

        const patternItem = shapeList[index];
        if (patternItem && patternItem.form) {
          customPanel = patternItem.form;
          useExternalPanel = true;
        }

        if (this.props.drawerRef.value?.show) {
          this.props.drawerRef.value.show({
            ...nodeData,
            patternItem: patternItem,
            lf
          }, customPanel, useExternalPanel ? 'external' : 'build_in');
        }
      }
    })
    eventCenter.on('edge:click', (event: any) => {
      if(props.viewer === true) {
        return
      }
      let edgeClick = props.edgeClick
      if(edgeClick && typeof edgeClick === 'function') {
        edgeClick(event)
      } else {
        this.props.drawerRef.value?.show({
          ...event,
          patternItem: {},
          lf
        })
      }
    })

  }
  initDndPanel(data: any){
    this.lf.extension.dndPanel.setPatternItems(data)
    this.dndPanel = data || []
  }
  initControl(data: any){
    const control = this.lf?.extension?.control
    if (control && control.controlItems) {
      control.controlItems = data || []
    }
  }
}
export default Flow
