<template>
  <div class="workflow-editor-page">
    <header class="workflow-editor-topbar">
      <div class="workflow-editor-title">
        <el-button @click="$emit('back')">返回</el-button>
        <el-input v-model="workflowName" placeholder="工作流名称" class="workflow-name-input" />
        <el-input v-model="workflowKey" placeholder="workflow key" class="workflow-key-input" />
        <el-input v-model="workflowDescription" placeholder="描述" class="workflow-desc-input" />
      </div>
      <div class="filters">
        <el-button type="primary" :loading="saving" @click="save">保存</el-button>
        <el-button type="success" :disabled="!workflowId" :loading="running" @click="runWorkflow">执行</el-button>
        <el-button @click="fitView()">适配画布</el-button>
      </div>
    </header>

    <div class="workflow-editor-body">
      <aside class="workflow-node-palette">
        <div class="section-title">节点库</div>
        <el-collapse v-model="openedCategories">
          <el-collapse-item v-for="group in groupedNodeDefinitions" :key="group.category" :title="categoryLabel(group.category)" :name="group.category">
            <button v-for="definition in group.items" :key="definition.type" class="palette-node" type="button" @click="addNode(definition)">
              <span>{{ definition.label }}</span>
              <small>{{ definition.type }}</small>
            </button>
          </el-collapse-item>
        </el-collapse>
      </aside>

      <main class="workflow-flow-wrap">
        <VueFlow
          v-model:nodes="flowNodes"
          v-model:edges="flowEdges"
          class="workflow-flow"
          :default-viewport="{ zoom: 0.9 }"
          :min-zoom="0.2"
          :max-zoom="2"
          fit-view-on-init
          @connect="onConnect"
          @node-click="onNodeClick"
          @pane-click="selectedNodeId = null"
        >
          <Background pattern-color="#cbd5e1" :gap="24" />
          <Controls />
        </VueFlow>
      </main>

      <aside class="workflow-inspector-panel">
        <div class="section-title">工作流变量</div>
        <div class="workflow-variable-list">
          <div v-for="(variable, name) in workflowVariables" :key="name" class="workflow-variable-row">
            <div class="workflow-variable-head">
              <strong>{{ name }}</strong>
              <el-button size="small" type="danger" @click="deleteVariable(name)">删除</el-button>
            </div>
            <div class="workflow-variable-fields">
              <el-select v-model="ensureVariableObject(name).type" size="small">
                <el-option label="文本" value="string" />
                <el-option label="数字" value="number" />
                <el-option label="布尔" value="boolean" />
              </el-select>
              <component
                :is="variableDefaultComponent(ensureVariableObject(name))"
                v-model="ensureVariableObject(name).default"
                v-bind="variableDefaultProps(ensureVariableObject(name))"
                placeholder="默认值"
              />
            </div>
            <el-input v-model="ensureVariableObject(name).description" size="small" placeholder="说明" />
          </div>
          <el-button class="add-variable-button" @click="addVariable">新增变量</el-button>
        </div>

        <template v-if="selectedNode">
          <div class="section-title">节点属性</div>
          <el-form label-width="86px" class="workflow-inspector-form">
            <el-form-item label="标题">
              <el-input v-model="selectedNode.data.title" @input="syncNodeLabel" />
            </el-form-item>
            <el-form-item label="类型">
              <el-tag>{{ selectedNode.data.nodeType }}</el-tag>
            </el-form-item>
          </el-form>

          <div class="section-title">参数</div>
          <el-form label-width="92px" class="workflow-inspector-form">
            <el-form-item v-for="(field, key) in selectedDefinition?.params || {}" :key="key" :label="field.label || key">
              <component
                :is="fieldComponent(field)"
                v-model="selectedNode.data.params[key]"
                v-bind="fieldProps(field)"
                class="workflow-field"
              >
                <el-option v-for="option in field.options || []" :key="option" :label="option" :value="option" />
              </component>
            </el-form-item>
            <div v-if="!Object.keys(selectedDefinition?.params || {}).length" class="muted">此节点没有固定参数。</div>
          </el-form>

          <div class="section-title">输入</div>
          <div v-for="(field, key) in selectedDefinition?.inputs || {}" :key="key" class="input-binding-row">
            <div class="input-binding-name">{{ field.label || key }}</div>
            <el-select v-model="inputBinding(key).source" class="input-source">
              <el-option label="固定值" value="literal" />
              <el-option label="变量" value="variable" />
              <el-option label="节点输出" value="node_output" />
              <el-option label="运行时" value="runtime" />
            </el-select>
            <el-input v-if="inputBinding(key).source === 'literal'" v-model="inputBinding(key).value" placeholder="值" />
            <el-input v-if="inputBinding(key).source === 'variable'" v-model="inputBinding(key).name" placeholder="变量名" />
            <template v-if="inputBinding(key).source === 'node_output'">
              <el-select v-model="inputBinding(key).node_id" placeholder="节点">
                <el-option v-for="node in flowNodes.filter((item) => item.id !== selectedNode.id)" :key="node.id" :label="node.data.title" :value="node.id" />
              </el-select>
              <el-input v-model="inputBinding(key).output" placeholder="输出名" />
            </template>
            <el-input v-if="inputBinding(key).source === 'runtime'" v-model="inputBinding(key).name" placeholder="运行时键名" />
          </div>
          <div v-if="!Object.keys(selectedDefinition?.inputs || {}).length" class="muted">此节点不需要输入。</div>

          <div class="section-title">连线</div>
          <el-table :data="selectedEdges" size="small" border>
            <el-table-column prop="label" label="连线" min-width="130" />
            <el-table-column label="类型" width="100">
              <template #default="{ row }">
                <el-select v-model="row.data.kind" size="small" @change="syncEdgeLabel(row)">
                  <el-option label="控制流" value="control" />
                  <el-option label="数据流" value="data" />
                </el-select>
              </template>
            </el-table-column>
            <el-table-column label="操作" width="74">
              <template #default="{ row }">
                <el-button size="small" type="danger" @click="deleteEdge(row.id)">删</el-button>
              </template>
            </el-table-column>
          </el-table>

          <div class="filters inspector-actions">
            <el-button type="danger" @click="deleteSelectedNode">删除节点</el-button>
          </div>
        </template>
        <div v-else class="muted">从左侧添加节点，或点击画布中的节点编辑参数和输入绑定。</div>

        <div class="section-title">执行结果</div>
        <pre class="workflow-run-output">{{ runOutput || '暂无执行结果' }}</pre>
      </aside>
    </div>
  </div>
</template>

<script setup>
import { computed, nextTick, onMounted, ref } from 'vue'
import { VueFlow, useVueFlow } from '@vue-flow/core'
import { Background } from '@vue-flow/background'
import { Controls } from '@vue-flow/controls'
import '@vue-flow/core/dist/style.css'
import '@vue-flow/core/dist/theme-default.css'
import '@vue-flow/controls/dist/style.css'
import { ElMessage, ElMessageBox } from 'element-plus'
import { api } from '../api'

const props = defineProps({
  workflowId: { type: Number, default: null },
})

const emit = defineEmits(['back', 'saved'])
const { fitView } = useVueFlow()

const nodeDefinitions = ref([])
const flowNodes = ref([])
const flowEdges = ref([])
const workflowName = ref('')
const workflowKey = ref('')
const workflowDescription = ref('')
const workflowVariables = ref({})
const workflowSettings = ref({ max_steps: 100, default_timeout_ms: 30000, on_unhandled_error: 'pause_for_user' })
const workflowId = ref(props.workflowId)
const selectedNodeId = ref(null)
const openedCategories = ref(['flow', 'mouse', 'keyboard'])
const saving = ref(false)
const running = ref(false)
const runOutput = ref('')

const selectedNode = computed(() => flowNodes.value.find((node) => node.id === selectedNodeId.value))
const selectedDefinition = computed(() => nodeDefinitions.value.find((item) => item.type === selectedNode.value?.data?.nodeType))
const selectedEdges = computed(() => flowEdges.value.filter((edge) => edge.source === selectedNodeId.value || edge.target === selectedNodeId.value))
const groupedNodeDefinitions = computed(() => {
  const groups = new Map()
  for (const item of nodeDefinitions.value) {
    if (!groups.has(item.category)) groups.set(item.category, [])
    groups.get(item.category).push(item)
  }
  return [...groups.entries()].map(([category, items]) => ({ category, items }))
})

function categoryLabel(category) {
  return {
    flow: '流程',
    mouse: '鼠标',
    keyboard: '键盘',
    text: '文本',
    program: '程序',
    screen: '屏幕',
    wait: '等待',
    human: '人工交互',
  }[category] || category
}

async function loadDefinitions() {
  const { data } = await api.get('/api/automation/workflow-nodes')
  nodeDefinitions.value = data.items || []
}

async function loadWorkflow() {
  if (!workflowId.value) {
    workflowName.value = `新工作流 ${new Date().toLocaleString()}`
    workflowKey.value = ''
    workflowDescription.value = ''
    workflowVariables.value = {}
    workflowSettings.value = { max_steps: 100, default_timeout_ms: 30000, on_unhandled_error: 'pause_for_user' }
    flowNodes.value = []
    flowEdges.value = []
    return
  }
  const { data } = await api.get(`/api/automation/workflows/${workflowId.value}`)
  workflowName.value = data.name
  workflowKey.value = data.workflow_key || ''
  workflowDescription.value = data.description || ''
  workflowVariables.value = data.variables || {}
  workflowSettings.value = data.settings || {}
  flowNodes.value = (data.nodes || []).map(workflowNodeToFlow)
  flowEdges.value = (data.edges || []).map(workflowEdgeToFlow)
}

function workflowNodeToFlow(node) {
  return {
    id: node.id,
    type: 'default',
    label: node.title || node.type,
    position: node.position || { x: 80, y: 80 },
    data: {
      title: node.title || node.type,
      nodeType: node.type,
      params: structuredClone(node.params || {}),
      inputs: structuredClone(node.inputs || {}),
    },
  }
}

function workflowEdgeToFlow(edge) {
  const kind = edge.kind || 'control'
  return {
    id: edge.id || `${edge.source}-${edge.target}-${Date.now()}`,
    source: edge.source,
    target: edge.target,
    sourceHandle: edge.source_port || null,
    targetHandle: edge.target_port || null,
    label: edgeLabel(kind),
    data: { kind },
    animated: kind === 'control',
    style: { stroke: kind === 'data' ? '#10b981' : '#2563eb' },
  }
}

function addNode(definition) {
  const index = flowNodes.value.length
  const node = {
    id: `node_${Date.now()}_${index}`,
    type: 'default',
    label: definition.label,
    position: { x: 120 + index * 40, y: 120 + index * 36 },
    data: {
      title: definition.label,
      nodeType: definition.type,
      params: defaultValues(definition.params || {}),
      inputs: {},
    },
  }
  flowNodes.value.push(node)
  selectedNodeId.value = node.id
  nextTick(() => fitView())
}

function defaultValues(fields) {
  const values = {}
  for (const [key, field] of Object.entries(fields)) {
    values[key] = structuredClone(field.default ?? defaultValueForType(field.type))
  }
  return values
}

function defaultValueForType(type) {
  if (type === 'number') return 0
  if (type === 'boolean') return false
  if (type === 'array') return []
  return ''
}

function onConnect(connection) {
  const kind = 'control'
  flowEdges.value.push({
    id: `edge_${Date.now()}`,
    ...connection,
    label: edgeLabel(kind),
    data: { kind },
    animated: true,
    style: { stroke: '#2563eb' },
  })
}

function onNodeClick(event) {
  selectedNodeId.value = event.node.id
}

function syncNodeLabel() {
  if (!selectedNode.value) return
  selectedNode.value.label = selectedNode.value.data.title
}

function syncEdgeLabel(edge) {
  edge.label = edgeLabel(edge.data.kind)
  edge.animated = edge.data.kind === 'control'
  edge.style = { stroke: edge.data.kind === 'data' ? '#10b981' : '#2563eb' }
}

function edgeLabel(kind) {
  return kind === 'data' ? '数据' : '控制'
}

function fieldComponent(field) {
  if (field.type === 'boolean') return 'el-switch'
  if (field.type === 'select') return 'el-select'
  if (field.type === 'number') return 'el-input-number'
  if (field.type === 'textarea') return 'el-input'
  return 'el-input'
}

function fieldProps(field) {
  if (field.type === 'textarea') return { type: 'textarea', rows: 4 }
  if (field.type === 'number') return { min: field.min, max: field.max }
  if (field.type === 'array') return { type: 'textarea', rows: 3, placeholder: 'JSON 数组或逗号分隔文本' }
  return {}
}

function inputBinding(key) {
  if (!selectedNode.value.data.inputs[key]) {
    selectedNode.value.data.inputs[key] = { source: 'literal', value: '' }
  }
  return selectedNode.value.data.inputs[key]
}

function ensureVariableObject(name) {
  if (!workflowVariables.value[name] || typeof workflowVariables.value[name] !== 'object') {
    workflowVariables.value[name] = {
      type: typeof workflowVariables.value[name],
      default: workflowVariables.value[name],
      description: '',
    }
  }
  workflowVariables.value[name].type ||= 'string'
  return workflowVariables.value[name]
}

function variableDefaultComponent(variable) {
  if (variable.type === 'number') return 'el-input-number'
  if (variable.type === 'boolean') return 'el-switch'
  return 'el-input'
}

function variableDefaultProps(variable) {
  if (variable.type === 'number') return { controlsPosition: 'right' }
  return {}
}

async function addVariable() {
  const { value } = await ElMessageBox.prompt('请输入变量名', '新增变量', {
    inputPattern: /^[A-Za-z_][A-Za-z0-9_]*$/,
    inputErrorMessage: '变量名只能使用字母、数字和下划线，且不能以数字开头',
  })
  if (workflowVariables.value[value]) {
    ElMessage.warning('变量已存在')
    return
  }
  workflowVariables.value[value] = { type: 'string', default: '', description: '' }
}

function deleteVariable(name) {
  delete workflowVariables.value[name]
}

function deleteEdge(edgeId) {
  flowEdges.value = flowEdges.value.filter((edge) => edge.id !== edgeId)
}

function deleteSelectedNode() {
  if (!selectedNodeId.value) return
  flowNodes.value = flowNodes.value.filter((node) => node.id !== selectedNodeId.value)
  flowEdges.value = flowEdges.value.filter((edge) => edge.source !== selectedNodeId.value && edge.target !== selectedNodeId.value)
  selectedNodeId.value = null
}

function buildPayload() {
  return {
    schema_version: 'workflow/v1',
    workflow_key: workflowKey.value.trim() || null,
    name: workflowName.value.trim(),
    description: workflowDescription.value,
    variables: workflowVariables.value,
    settings: workflowSettings.value,
    nodes: flowNodes.value.map((node) => ({
      id: node.id,
      type: node.data.nodeType,
      title: node.data.title,
      position: node.position,
      params: node.data.params || {},
      inputs: node.data.inputs || {},
    })),
    edges: flowEdges.value.map((edge) => ({
      id: edge.id,
      kind: edge.data?.kind || 'control',
      source: edge.source,
      source_port: edge.sourceHandle || (edge.data?.kind === 'data' ? 'value' : 'success'),
      target: edge.target,
      target_port: edge.targetHandle || (edge.data?.kind === 'data' ? 'value' : 'run'),
    })),
  }
}

async function save() {
  if (!workflowName.value.trim()) {
    ElMessage.warning('请输入工作流名称')
    return
  }
  saving.value = true
  try {
    const payload = buildPayload()
    const { data } = workflowId.value
      ? await api.put(`/api/automation/workflows/${workflowId.value}`, payload)
      : await api.post('/api/automation/workflows', payload)
    workflowId.value = data.id
    ElMessage.success('已保存')
    emit('saved', data.id)
  } finally {
    saving.value = false
  }
}

async function runWorkflow() {
  if (!workflowId.value) return
  running.value = true
  try {
    const { data } = await api.post(`/api/automation/workflows/${workflowId.value}/run`, {})
    runOutput.value = JSON.stringify(data, null, 2)
    ElMessage[data.status === 'SUCCESS' ? 'success' : 'warning'](data.status === 'SUCCESS' ? '工作流执行完成' : '工作流执行中止')
  } catch (error) {
    ElMessage.error(error.response?.data?.detail || '执行工作流失败')
  } finally {
    running.value = false
  }
}

onMounted(async () => {
  await loadDefinitions()
  await loadWorkflow()
})
</script>
