import { ref, onMounted, onUnmounted, nextTick, reactive, computed, type Ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import LogicFlow, {
  RectNode,
  RectNodeModel,
  CircleNode,
  CircleNodeModel,
  PolygonNode,
  PolygonNodeModel,
} from '@logicflow/core'
import { Menu, Snapshot } from '@logicflow/extension'
import '@logicflow/core/dist/style/index.css'
import '@logicflow/extension/lib/style/index.css'
import { ElMessage } from 'element-plus'
import type { FormRules } from 'element-plus'
import { listRole } from '@/api/system/role'
import { addDefinition, updateDefinition, getDefinition } from '@/api/flow/definition'
import type { Role } from '@/types/system'
import type { FlowDefinition, FormField, FormFieldOption } from '@/types/flow'

/* eslint-disable @typescript-eslint/no-explicit-any */
export function useFlowDesigner(lfContainer: Ref<HTMLDivElement | undefined>) {
  const route = useRoute()
  const router = useRouter()

  let lf: LogicFlow | null = null
  const lfRef = ref<any>(null)

  const mode = computed(() => (route.query.mode as string) || '')
  const flowId = computed(() => (route.query.id as string) || '')
  const flowCode = computed(() => (route.query.code as string) || '')
  const flowName = computed(() => (route.query.name as string) || '')
  const flowCategory = computed(() => (route.query.category as string) || '')
  const flowDescription = computed(() => (route.query.description as string) || '')
  const flowInfoVisible = computed(() => mode.value === 'create' || mode.value === 'edit')

  const selectedNode = ref<any>(null)
  const roleList = ref<Role[]>([])
  const nodeProps = reactive<Record<string, any>>({
    assigneeType: 'ROLE',
    assigneeValue: '',
    approveMode: 'or',
    timeoutHours: undefined as number | undefined,
    timeoutAction: 'remind',
    approveTimeField: '',
    ccUsers: '',
    subNodesEnabled: false,
    subNodeMode: 'parallel',
    subNodes: [] as any[],
  })

  // 条件节点出连线配置
  const outgoingEdges = ref<any[]>([])

  function loadOutgoingEdges(nodeId?: string) {
    if (!lf) {
      outgoingEdges.value = []
      return
    }
    const id = nodeId || selectedNode.value?.id
    if (!id) {
      outgoingEdges.value = []
      return
    }
    const graphData = lf.getGraphData()
    const edges = (graphData.edges || []).filter((e: any) => e.sourceNodeId === id)
    outgoingEdges.value = edges.map((e: any) => ({
      ...e,
      properties: {
        condition: '',
        isDefault: false,
        branchName: '',
        ...(e.properties || {}),
      },
    }))
  }

  function getEdgeTargetName(edge: any): string {
    if (!lf || !edge?.targetNodeId) return '—'
    try {
      const node = lf.getNodeData(edge.targetNodeId)
      return node?.text?.value || node?.text || '未命名节点'
    } catch {
      return '—'
    }
  }

  function getEdgeDisplayText(edge: any): string {
    const props = edge.properties || {}
    if (props.branchName) return props.branchName
    if (props.isDefault) return '默认'
    if (props.condition) return props.condition
    return ''
  }

  function syncEdgeToLf(edge: any) {
    if (!lf || !edge?.id) return
    const props = edge.properties || {}
    const displayText = getEdgeDisplayText(edge)
    lf.setEdgeData(edge.id, {
      properties: { ...props },
      text: displayText ? { value: displayText } : undefined,
    })
  }

  function onDefaultChange(edge: any) {
    if (edge.properties.isDefault) {
      edge.properties.condition = ''
      // 同一条件节点下只能有一个默认分支
      const nodeId = edge.sourceNodeId
      outgoingEdges.value.forEach((e: any) => {
        if (e.id !== edge.id && e.sourceNodeId === nodeId) {
          e.properties.isDefault = false
          syncEdgeToLf(e)
        }
      })
    }
    syncEdgeToLf(edge)
  }

  function onBranchBlur(edge: any) {
    syncEdgeToLf(edge)
  }

  function generateSubNodeId(): string {
    return 'sub-' + Date.now() + '-' + Math.random().toString(36).slice(2, 8)
  }

  function getDefaultProps(type: string) {
    if (type === 'approval-node')
      return {
        assigneeType: 'ROLE',
        assigneeValue: '',
        approveMode: 'or',
        timeoutHours: undefined,
        timeoutAction: 'remind',
        approveTimeField: '',
        subNodesEnabled: false,
        subNodeMode: 'parallel',
        subNodes: [],
      }
    if (type === 'cc-node') return { ccUsers: '' }
    return {}
  }

  function saveCurrentNodeProps() {
    if (selectedNode.value && lf) {
      const type = selectedNode.value.type
      const defaultProps = getDefaultProps(type)
      // 只保存当前节点类型相关的属性，避免不同类型节点属性互相污染
      const props: Record<string, any> = JSON.parse(JSON.stringify(defaultProps))
      if (type === 'approval-node') {
        props.assigneeType = nodeProps.assigneeType ?? 'ROLE'
        props.assigneeValue = nodeProps.assigneeValue ?? ''
        props.approveMode = nodeProps.approveMode ?? 'or'
        props.timeoutHours = nodeProps.timeoutHours
        props.timeoutAction = nodeProps.timeoutAction ?? 'remind'
        props.approveTimeField = nodeProps.approveTimeField ?? ''
        props.subNodesEnabled = nodeProps.subNodesEnabled ?? false
        props.subNodeMode = nodeProps.subNodeMode ?? 'parallel'
        props.subNodes = Array.isArray(nodeProps.subNodes) ? nodeProps.subNodes : []
      } else if (type === 'cc-node') {
        props.ccUsers = nodeProps.ccUsers ?? ''
      }
      lf.setProperties(selectedNode.value.id, props)
      // 同步子节点数量角标到节点文本
      if (type === 'approval-node') {
        syncNodeTextWithSubNodeBadge(selectedNode.value.id)
      }
      // 通知画布刷新子节点 overlay
      lf.emit('properties:changed', { nodeId: selectedNode.value.id })
    }
  }

  function getNodeRawText(nodeId: string): string {
    if (!lf) return ''
    try {
      const node = lf.getNodeData(nodeId)
      const text = node?.text?.value || node?.text || ''
      return String(text).replace(/ \(\+\d+\)$/, '')
    } catch {
      return ''
    }
  }

  function syncNodeTextWithSubNodeBadge(nodeId: string) {
    if (!lf) return
    const rawText = getNodeRawText(nodeId)
    if (!rawText) return
    // 不再把子节点数量拼进节点文本，改为画布浮层角标
    lf.setNodeText(nodeId, rawText)
  }

  function loadNodeProps(data: any) {
    const props = data.properties || getDefaultProps(data.type)
    const cloned = JSON.parse(JSON.stringify(props))
    // 先重置为默认值，避免上一个节点的属性残留
    Object.assign(nodeProps, getDefaultProps(data.type))
    // 兼容旧格式：approver + approveType -> 新格式
    if (data.type === 'approval-node') {
      const supportedTypes = ['ROLE', 'SELF']
      let assigneeType = cloned.assigneeType ?? 'ROLE'
      let assigneeValue = cloned.assigneeValue ?? ''
      const approveMode = cloned.approveMode ?? cloned.approveType ?? 'or'
      if (!cloned.assigneeType && !cloned.assigneeValue && cloned.approver) {
        assigneeType = 'ROLE'
        assigneeValue = cloned.approver
      }
      // 当前设计器只支持 ROLE / SELF，其它旧类型降级为 ROLE 并清空值
      if (!supportedTypes.includes(assigneeType)) {
        assigneeType = 'ROLE'
        assigneeValue = ''
      }
      // SELF 不需要审批角色值
      if (assigneeType === 'SELF') {
        assigneeValue = ''
      }
      nodeProps.assigneeType = assigneeType
      nodeProps.assigneeValue = assigneeValue
      nodeProps.approveMode = approveMode
      nodeProps.timeoutHours = cloned.timeoutHours ?? undefined
      nodeProps.timeoutAction = cloned.timeoutAction ?? 'remind'
      nodeProps.approveTimeField = cloned.approveTimeField ?? ''
      nodeProps.subNodesEnabled = cloned.subNodesEnabled === true
      nodeProps.subNodeMode = cloned.subNodeMode ?? 'parallel'
      nodeProps.subNodes = Array.isArray(cloned.subNodes)
        ? cloned.subNodes.map((s: any) => ({
            id: s.id || generateSubNodeId(),
            name: s.name || '',
            assigneeType: s.assigneeType ?? 'ROLE',
            assigneeValue: s.assigneeValue ?? '',
            approveMode: s.approveMode ?? 'or',
            timeoutHours: s.timeoutHours ?? undefined,
            timeoutAction: s.timeoutAction ?? 'remind',
          }))
        : []
    } else if (data.type === 'cc-node') {
      nodeProps.ccUsers = cloned.ccUsers ?? ''
    }
  }

  function registerNodes() {
    if (!lf) return

    class StartNodeModel extends CircleNodeModel {
      setAttributes() {
        this.r = 30
        if (!this.text.value) this.text.value = '开始'
      }
      getNodeStyle() {
        const style = super.getNodeStyle()
        style.fill = '#67C23A'
        style.stroke = '#67C23A'
        return style
      }
      getTextStyle() {
        const style = super.getTextStyle()
        style.color = '#fff'
        return style
      }
    }
    lf.register({ type: 'start-node', view: CircleNode, model: StartNodeModel })

    class ApprovalNodeModel extends RectNodeModel {
      setAttributes() {
        this.width = 160
        this.height = 60
        this.radius = 8
        if (!this.text.value) this.text.value = '审批节点'
      }
      getNodeStyle() {
        const style = super.getNodeStyle()
        style.fill = '#fff'
        style.stroke = '#409EFF'
        style.strokeWidth = 1
        return style
      }
    }
    lf.register({ type: 'approval-node', view: RectNode, model: ApprovalNodeModel })

    class CcNodeModel extends RectNodeModel {
      setAttributes() {
        this.width = 160
        this.height = 60
        this.radius = 8
        if (!this.text.value) this.text.value = '抄送节点'
      }
      getNodeStyle() {
        const style = super.getNodeStyle()
        style.fill = '#fff'
        style.stroke = '#E6A23C'
        style.strokeWidth = 1
        return style
      }
    }
    lf.register({ type: 'cc-node', view: RectNode, model: CcNodeModel })

    class ConditionNodeModel extends PolygonNodeModel {
      setAttributes() {
        this.points = [
          [60, 0],
          [120, 40],
          [60, 80],
          [0, 40],
        ]
        if (!this.text.value) this.text.value = '条件'
      }
      getNodeStyle() {
        const style = super.getNodeStyle()
        style.fill = '#fff'
        style.stroke = '#909399'
        return style
      }
    }
    lf.register({ type: 'condition-node', view: PolygonNode, model: ConditionNodeModel })

    class EndNodeModel extends CircleNodeModel {
      setAttributes() {
        this.r = 30
        if (!this.text.value) this.text.value = '结束'
      }
      getNodeStyle() {
        const style = super.getNodeStyle()
        style.fill = '#F56C6C'
        style.stroke = '#F56C6C'
        return style
      }
      getTextStyle() {
        const style = super.getTextStyle()
        style.color = '#fff'
        return style
      }
    }
    lf.register({ type: 'end-node', view: CircleNode, model: EndNodeModel })
  }

  function defaultNodes() {
    return [
      { id: 'start-1', type: 'start-node', x: 200, y: 100, text: '开始' },
      { id: 'end-1', type: 'end-node', x: 200, y: 500, text: '结束' },
    ]
  }

  function initLogicFlow() {
    if (!lfContainer.value) return

    lf = new LogicFlow({
      container: lfContainer.value,
      grid: true,
      plugins: [Menu, Snapshot],
      pluginsOptions: {
        menu: {
          nodeMenu: [
            {
              text: '删除',
              callback(node: any) {
                lf?.deleteNode(node.id)
              },
            },
          ],
        },
      } as any,
    })
    lfRef.value = lf

    registerNodes()

    lf.on('node:click', ({ data }: any) => {
      saveCurrentNodeProps()
      selectedNode.value = data
      loadNodeProps(data)
      loadOutgoingEdges(data.id)
    })

    lf.on('blank:click', () => {
      saveCurrentNodeProps()
      selectedNode.value = null
      outgoingEdges.value = []
    })

    // 当条件节点的出连线发生变化时，刷新右侧分支配置面板
    lf.on('edge:add', ({ data }: any) => {
      if (selectedNode.value?.id && data?.sourceNodeId === selectedNode.value.id) {
        loadOutgoingEdges(selectedNode.value.id)
      }
    })
    lf.on('edge:delete', ({ data }: any) => {
      if (selectedNode.value?.id && data?.sourceNodeId === selectedNode.value.id) {
        loadOutgoingEdges(selectedNode.value.id)
      }
    })

    // 编辑模式：加载已有流程图
    if (mode.value === 'edit' && flowId.value) {
      getDefinition(Number(flowId.value))
        .then((def: FlowDefinition) => {
          parseFormSchema(def.formSchema)
          if (def.flowJson) {
            try {
              const parsed = JSON.parse(def.flowJson)
              const graphData = convertToFrontendFormat(parsed)
              lf?.render(graphData)
              nextTick(() => syncAllSubNodeBadges())
            } catch {
              lf?.render({ nodes: defaultNodes(), edges: [] })
            }
          } else {
            lf?.render({ nodes: defaultNodes(), edges: [] })
          }
        })
        .catch(() => {
          lf?.render({ nodes: defaultNodes(), edges: [] })
        })
    } else {
      lf.render({ nodes: defaultNodes(), edges: [] })
    }
    nextTick(() => syncAllSubNodeBadges())
  }

  function syncAllSubNodeBadges() {
    if (!lf) return
    const graphData = lf.getGraphData()
    for (const node of graphData.nodes || []) {
      if (node.type !== 'approval-node') continue
      syncNodeTextWithSubNodeBadge(node.id)
    }
  }
  const typeToBackend: Record<string, string> = {
    'start-node': 'start',
    'approval-node': 'approval',
    'cc-node': 'cc',
    'condition-node': 'condition',
    'end-node': 'end',
  }
  const typeToFrontend: Record<string, string> = {
    start: 'start-node',
    approval: 'approval-node',
    cc: 'cc-node',
    condition: 'condition-node',
    end: 'end-node',
  }

  // 将 LogicFlow 的 graphData 转换为后端格式
  function convertToBackendFormat(graphData: any) {
    const data = JSON.parse(JSON.stringify(graphData))
    if (data.nodes) {
      data.nodes = data.nodes.map((node: any) => {
        const n = { ...node }
        if (n.type && typeToBackend[n.type]) {
          n.type = typeToBackend[n.type]
        }
        // text -> name
        if (n.text !== undefined) {
          n.name = typeof n.text === 'object' ? n.text.value : n.text
          // 去掉子节点数量角标，避免保存到后端
          n.name = String(n.name).replace(/ \(\+\d+\)$/, '')
          delete n.text
        }
        return n
      })
    }
    // 将 LogicFlow edge.properties 转换为后端的 edge.condition 结构
    if (data.edges) {
      data.edges = data.edges.map((edge: any) => {
        const e = { ...edge }
        const props = e.properties || {}
        e.condition = {
          condition: props.condition || '',
          isDefault: props.isDefault ?? !props.condition,
          branchName: props.branchName || '',
        }
        // 清理 LogicFlow 运行时不需要的属性，避免后端序列化冗余
        if (e.text !== undefined && (!e.text || !e.text.value)) {
          delete e.text
        }
        delete e.properties
        return e
      })
    }
    return data
  }

  // 将后端的 graphData 转换为 LogicFlow 格式
  function convertToFrontendFormat(graphData: any) {
    const data = JSON.parse(JSON.stringify(graphData))

    // 兼容旧格式：条件表达式写在节点 properties.condition 上，需要迁移到连线
    if (data.nodes && data.edges) {
      data.nodes.forEach((node: any) => {
        if ((node.type === 'condition' || node.type === 'condition-node') && node.properties?.condition) {
          const nodeCondition = String(node.properties.condition)
          const outEdges = data.edges.filter((e: any) => e.sourceNodeId === node.id)
          if (outEdges.length > 0) {
            // 第一条连线作为条件分支，其余作为默认分支
            outEdges.forEach((e: any, idx: number) => {
              if (!e.condition) {
                e.condition = {}
              }
              if (idx === 0) {
                e.condition.condition = nodeCondition
                e.condition.isDefault = false
              } else {
                e.condition.condition = ''
                e.condition.isDefault = true
              }
            })
          }
          delete node.properties.condition
        }
      })
    }

    if (data.edges) {
      data.edges = data.edges.map((edge: any) => {
        const e = { ...edge }
        // 将后端的 edge.condition 转换为 LogicFlow 的 edge.properties
        const conditionMap = e.condition || {}
        e.properties = {
          condition: conditionMap.condition || '',
          isDefault: conditionMap.isDefault ?? !conditionMap.condition,
          branchName: conditionMap.branchName || '',
        }
        // 设置/清理连线文本
        const displayText = e.properties.branchName || (!e.properties.isDefault && e.properties.condition)
        if (displayText) {
          e.text = { value: displayText }
        } else {
          delete e.text
        }
        delete e.condition
        return e
      })
    }

    if (data.nodes) {
      data.nodes = data.nodes.map((node: any) => {
        const n = { ...node }
        if (n.type && typeToFrontend[n.type]) {
          n.type = typeToFrontend[n.type]
        }
        // name -> text
        if (n.name !== undefined) {
          n.text = String(n.name).replace(/ \(\+\d+\)$/, '')
          delete n.name
        }
        return n
      })
    }
    return data
  }

  function handleDrop(e: DragEvent) {
    e.preventDefault()
    const dataStr = e.dataTransfer?.getData('application/json')
    if (!dataStr || !lf || !lfContainer.value) return
    const nodeData = JSON.parse(dataStr)
    const rect = lfContainer.value.getBoundingClientRect()
    lf.addNode({
      type: nodeData.type,
      x: e.clientX - rect.left,
      y: e.clientY - rect.top,
      text: nodeData.label,
    })
  }

  function updateNodeName() {
    if (!lf || !selectedNode.value) return
    lf.setNodeText(selectedNode.value.id, selectedNode.value.text?.value || '')
  }

  // 保存流程
  const saveDialogVisible = ref(false)
  const saveForm = reactive({
    code: '',
    name: '',
    category: '',
    description: '',
  })
  const saveFormRules: FormRules = {
    code: [{ required: true, message: '请输入流程编码', trigger: 'blur' }],
    name: [{ required: true, message: '请输入流程名称', trigger: 'blur' }],
  }

  const formFields = ref<FormField[]>([])
  const fieldTypeOptions = [
    { label: '文本', value: 'text' },
    { label: '多行文本', value: 'textarea' },
    { label: '数字', value: 'number' },
    { label: '日期', value: 'date' },
    { label: '下拉选择', value: 'select' },
  ]

  function addFormField() {
    formFields.value.push({ name: '', label: '', type: 'text', required: false })
  }

  function removeFormField(index: number) {
    formFields.value.splice(index, 1)
  }

  function getFormSchema(): string {
    const validFields = formFields.value.filter((f) => f.name.trim() && f.label.trim())
    return validFields.length > 0 ? JSON.stringify(validFields) : ''
  }

  function parseFormSchema(schema?: string) {
    if (!schema) return
    try {
      const parsed = JSON.parse(schema)
      if (Array.isArray(parsed)) {
        formFields.value = parsed
      }
    } catch {
      formFields.value = []
    }
  }

  // 下拉选项编辑
  const optionDialogVisible = ref(false)
  const optionEditingIndex = ref<number | null>(null)
  const optionEditingField = ref<FormField | null>(null)
  const optionList = ref<FormFieldOption[]>([])

  function openOptionDialog(index: number) {
    optionEditingIndex.value = index
    optionEditingField.value = formFields.value[index]
    const rawOptions = optionEditingField.value.options || []
    optionList.value = rawOptions.map((opt: any) => {
      if (typeof opt === 'string') {
        return { label: opt, value: opt }
      }
      return { label: String(opt.label ?? opt.value), value: opt.value }
    })
    optionDialogVisible.value = true
  }

  function addOption() {
    optionList.value.push({ label: '', value: '' })
  }

  function removeOption(index: number) {
    optionList.value.splice(index, 1)
  }

  function saveOptions() {
    if (optionEditingIndex.value === null || !optionEditingField.value) return
    const validOptions = optionList.value.filter(
      (opt) => String(opt.label).trim() !== '' && String(opt.value).trim() !== ''
    )
    formFields.value[optionEditingIndex.value].options = validOptions
    formFields.value[optionEditingIndex.value].multiple = optionEditingField.value.multiple
    optionDialogVisible.value = false
  }

  function validateFlow(graphData: any): string | null {
    const nodes = graphData.nodes || []
    const edges = graphData.edges || []
    if (nodes.length === 0) return '流程图不能为空'
    const startNodes = nodes.filter((n: any) => n.type === 'start-node' || n.type === 'start')
    const endNodes = nodes.filter((n: any) => n.type === 'end-node' || n.type === 'end')
    if (startNodes.length === 0) return '流程图缺少开始节点'
    if (endNodes.length === 0) return '流程图缺少结束节点'
    if (startNodes.length > 1) return '流程图只能有一个开始节点'
    // 检查审批节点是否配置了审批对象
    for (const node of nodes) {
      if (node.type === 'approval-node' || node.type === 'approval') {
        const props = node.properties || {}
        const assigneeType = props.assigneeType ?? 'ROLE'
        const assigneeValue = props.assigneeValue || props.approver
        if (assigneeType === 'ROLE' && !assigneeValue && props.subNodesEnabled !== true) {
          return `审批节点 "${node.text || node.name}" 未选择审批角色`
        }
        if (props.subNodesEnabled === true) {
          const subNodes = props.subNodes || []
          if (subNodes.length === 0) {
            return `审批节点 "${node.text || node.name}" 已启用子节点，请至少配置一个子节点`
          }
          for (let i = 0; i < subNodes.length; i++) {
            const sub = subNodes[i]
            const subAssigneeType = sub.assigneeType ?? 'ROLE'
            const subAssigneeValue = sub.assigneeValue
            if (subAssigneeType === 'ROLE' && !subAssigneeValue) {
              return `审批节点 "${node.text || node.name}" 的子节点 ${i + 1} 未选择审批角色`
            }
          }
        }
      }
    }
    // 检查孤立节点
    const connectedNodeIds = new Set<string>()
    for (const edge of edges) {
      connectedNodeIds.add(edge.sourceNodeId)
      connectedNodeIds.add(edge.targetNodeId)
    }
    for (const node of nodes) {
      if (
        !connectedNodeIds.has(node.id) &&
        node.type !== 'start-node' &&
        node.type !== 'start' &&
        node.type !== 'end-node' &&
        node.type !== 'end'
      ) {
        return `节点 "${node.text || node.name}" 是孤立节点，请删除或连接`
      }
    }
    // 检查条件分支：有且只能有一个默认分支，非默认分支必须填写条件
    const sourceMap: Record<string, any[]> = {}
    for (const edge of edges) {
      if (!sourceMap[edge.sourceNodeId]) sourceMap[edge.sourceNodeId] = []
      sourceMap[edge.sourceNodeId].push(edge)
    }
    for (const node of nodes) {
      if (node.type === 'condition-node' || node.type === 'condition') {
        const outEdges = sourceMap[node.id] || []
        if (outEdges.length > 1) {
          const defaultEdges = outEdges.filter((e: any) => {
            const props = e.properties || {}
            return props.isDefault || (!props.condition && !e.condition)
          })
          if (defaultEdges.length === 0) {
            return `条件节点 "${node.text || node.name}" 需要至少一条默认分支`
          }
          if (defaultEdges.length > 1) {
            return `条件节点 "${node.text || node.name}" 只能有一条默认分支`
          }
          const invalid = outEdges.some((e: any) => {
            const props = e.properties || {}
            return !props.isDefault && !props.condition && !e.condition
          })
          if (invalid) {
            return `条件节点 "${node.text || node.name}" 的非默认分支必须填写条件表达式`
          }
        }
      }
    }
    return null
  }

  async function handleSave() {
    if (!lf) return
    saveCurrentNodeProps()
    const rawGraphData = lf.getGraphData()
    const error = validateFlow(rawGraphData)
    if (error) {
      ElMessage.warning(error)
      return
    }

    // 统一弹出保存弹窗，方便配置流程表单字段
    if (mode.value === 'create') {
      saveForm.code = flowCode.value
      saveForm.name = flowName.value
      saveForm.category = flowCategory.value
      saveForm.description = flowDescription.value
      formFields.value = []
    } else if (mode.value === 'edit' && flowId.value) {
      saveForm.code = flowCode.value
      saveForm.name = flowName.value
      saveForm.category = flowCategory.value
      saveForm.description = flowDescription.value
      // formFields 在编辑模式加载流程时已通过 parseFormSchema 填充
    } else {
      saveForm.code = ''
      saveForm.name = ''
      saveForm.category = ''
      saveForm.description = ''
      formFields.value = []
    }
    saveDialogVisible.value = true
  }

  async function submitSave() {
    if (!lf) return
    saveCurrentNodeProps()
    const rawGraphData = lf.getGraphData()
    const error = validateFlow(rawGraphData)
    if (error) {
      ElMessage.warning(error)
      return
    }
    const graphData = convertToBackendFormat(rawGraphData)

    if (mode.value === 'create') {
      const data: Partial<FlowDefinition> = {
        code: saveForm.code,
        name: saveForm.name,
        category: saveForm.category,
        description: saveForm.description,
        formSchema: getFormSchema(),
        flowJson: JSON.stringify(graphData),
        status: 0,
      }
      await addDefinition(data)
      ElMessage.success('流程新增成功')
      saveDialogVisible.value = false
      router.push('/flow/definition')
    } else if (mode.value === 'edit' && flowId.value) {
      const data: Partial<FlowDefinition> = {
        id: Number(flowId.value),
        code: saveForm.code,
        name: saveForm.name,
        category: saveForm.category,
        description: saveForm.description,
        formSchema: getFormSchema(),
        flowJson: JSON.stringify(graphData),
      }
      const newId = await updateDefinition(data)
      if (newId !== Number(flowId.value)) {
        ElMessage.success('流程已创建为新版本，请重新发布')
      } else {
        ElMessage.success('流程修改成功')
      }
      saveDialogVisible.value = false
      router.push('/flow/definition')
    } else {
      const data: Partial<FlowDefinition> = {
        code: saveForm.code,
        name: saveForm.name,
        category: saveForm.category,
        description: saveForm.description,
        formSchema: getFormSchema(),
        flowJson: JSON.stringify(graphData),
        status: 0,
      }
      await addDefinition(data)
      ElMessage.success('流程保存成功')
      saveDialogVisible.value = false
      router.push('/flow/definition')
    }
  }

  function deleteSelectedNode() {
    if (!lf || !selectedNode.value) return
    lf.deleteNode(selectedNode.value.id)
    selectedNode.value = null
    outgoingEdges.value = []
  }

  function selectNodeById(nodeId: string) {
    if (!lf) return
    try {
      const nodeData = lf.getNodeData(nodeId)
      if (!nodeData) return
      lf.selectElementById(nodeId)
      saveCurrentNodeProps()
      selectedNode.value = nodeData
      loadNodeProps(nodeData)
      loadOutgoingEdges(nodeData.id)
    } catch {
      // ignore
    }
  }

  function handleClear() {
    if (!lf) return
    lf.clearData()
    selectedNode.value = null
  }

  function goBack() {
    router.push('/flow/definition')
  }

  async function loadRoles() {
    try {
      const res = await listRole({ pageNum: 1, pageSize: 100 })
      roleList.value = res.list
    } catch {
      /* ignore */
    }
  }

  onMounted(() => {
    // 防止快速进入/离开设计器时重复创建 LogicFlow 实例（v1.x 无 destroy 方法）
    if (lf) {
      if (typeof lf.destroy === 'function') {
        lf.destroy()
      }
      lf = null
    }
    nextTick(initLogicFlow)
    loadRoles()
  })

  onUnmounted(() => {
    if (lf) {
      if (typeof lf.destroy === 'function') {
        lf.destroy()
      }
      lf = null
    }
    selectedNode.value = null
  })

  return {
    // flow info
    mode,
    flowId,
    flowCode,
    flowName,
    flowCategory,
    flowDescription,
    flowInfoVisible,
    // logic flow / selection
    selectedNode,
    outgoingEdges,
    roleList,
    nodeProps,
    lfRef,
    // property panel helpers
    loadOutgoingEdges,
    getEdgeTargetName,
    onDefaultChange,
    onBranchBlur,
    saveCurrentNodeProps,
    loadNodeProps,
    updateNodeName,
    generateSubNodeId,
    deleteSelectedNode,
    selectNodeById,
    // save dialog
    saveDialogVisible,
    saveForm,
    saveFormRules,
    formFields,
    fieldTypeOptions,
    addFormField,
    removeFormField,
    getFormSchema,
    parseFormSchema,
    // option dialog
    optionDialogVisible,
    optionEditingIndex,
    optionEditingField,
    optionList,
    openOptionDialog,
    addOption,
    removeOption,
    saveOptions,
    // toolbar actions
    handleSave,
    submitSave,
    handleClear,
    goBack,
    // drag/drop
    handleDrop,
  }
}
