<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>
              <em>{{ definition.description }}</em>
            </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 />
          <template #node-default="{ id, data, selected }">
            <div class="workflow-card-node" :class="{ selected, collapsed: data.collapsed }">
              <div class="workflow-card-head">
                <div class="workflow-card-title-wrap">
                  <div class="workflow-card-type">{{ nodeDefinition(data.nodeType)?.label || data.nodeType }}</div>
                  <div class="workflow-card-title">{{ data.title }}</div>
                </div>
                <button class="workflow-card-toggle" type="button" @click.stop="toggleNodeCollapsed(id)">
                  {{ data.collapsed ? '展开' : '折叠' }}
                </button>
              </div>
              <div class="workflow-card-desc">{{ nodeDefinition(data.nodeType)?.description || data.nodeType }}</div>
              <div v-if="!data.collapsed" class="workflow-card-body">
                <div class="workflow-card-section">
                  <strong>参数</strong>
                  <span v-if="!nodeParamEntries(data).length">无</span>
                  <span v-for="item in nodeParamEntries(data)" :key="item.key" class="workflow-card-chip">
                    {{ item.label }}={{ shortValue(item.value) }}
                  </span>
                </div>
                <div class="workflow-card-section">
                  <strong>输入</strong>
                  <span v-if="!nodeInputEntries(data).length">无</span>
                  <span v-for="item in nodeInputEntries(data)" :key="item.key" class="workflow-card-chip input">
                    {{ item.label }}←{{ bindingSummary(item.binding) }}
                  </span>
                </div>
                <div class="workflow-card-section">
                  <strong>输出</strong>
                  <span v-if="!nodeOutputEntries(data.nodeType).length">无</span>
                  <span v-for="item in nodeOutputEntries(data.nodeType).slice(0, 4)" :key="item.key" class="workflow-card-chip output">
                    {{ item.key }}:{{ item.type }}
                  </span>
                  <span v-if="nodeOutputEntries(data.nodeType).length > 4" class="workflow-card-more">
                    +{{ nodeOutputEntries(data.nodeType).length - 4 }}
                  </span>
                </div>
              </div>
            </div>
          </template>
        </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-option label="对象" value="object" />
                <el-option label="数组" value="array" />
              </el-select>
              <el-input
                v-if="['object', 'array'].includes(ensureVariableObject(name).type)"
                :model-value="variableJsonText(ensureVariableObject(name).default)"
                type="textarea"
                :rows="5"
                placeholder="JSON"
                @change="updateVariableJson(name, $event)"
              />
              <component
                v-else
                :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-item label="说明">
              <div class="node-description">{{ selectedDefinition?.description || '暂无说明' }}</div>
            </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-select v-model="inputBinding(key).output" placeholder="输出">
                <el-option v-for="output in outputEntriesForNode(inputBinding(key).node_id)" :key="output.key" :label="`${output.label} (${output.key})`" :value="output.key" />
              </el-select>
            </template>
            <el-input v-if="inputBinding(key).source === 'runtime'" v-model="inputBinding(key).name" placeholder="运行时键名" />
            <div v-if="field.description" class="field-help">{{ field.description }}</div>
          </div>
          <div v-if="!Object.keys(selectedDefinition?.inputs || {}).length" class="muted">此节点不需要输入。</div>

          <div class="section-title">输出数据结构</div>
          <el-table :data="nodeOutputEntries(selectedNode.data.nodeType)" size="small" border empty-text="此节点没有声明输出">
            <el-table-column prop="key" label="字段" width="110" />
            <el-table-column prop="label" label="含义" min-width="130" />
            <el-table-column prop="type" label="类型" width="90" />
            <el-table-column prop="description" label="说明" min-width="150" show-overflow-tooltip />
          </el-table>

          <div class="section-title">相关连线</div>
          <el-table :data="selectedEdges" size="small" border>
            <el-table-column label="来源" min-width="150">
              <template #default="{ row }">
                {{ edgeEndpointLabel(row.source, row.sourceHandle || edgeSourcePort(row)) }}
              </template>
            </el-table-column>
            <el-table-column label="目标" min-width="150">
              <template #default="{ row }">
                {{ edgeEndpointLabel(row.target, row.targetHandle || edgeTargetPort(row)) }}
              </template>
            </el-table-column>
            <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>
        <el-table :data="flowEdges" size="small" border empty-text="暂无连线">
          <el-table-column label="连线" min-width="230">
            <template #default="{ row }">
              {{ readableEdgeLabel(row) }}
            </template>
          </el-table-column>
          <el-table-column label="类型" width="82">
            <template #default="{ row }">
              <el-tag size="small" :type="row.data?.kind === 'data' ? 'success' : 'primary'">
                {{ edgeKindLabel(row.data?.kind) }}
              </el-tag>
            </template>
          </el-table-column>
        </el-table>

        <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', 'task-created'])
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', 'browser', 'vision', 'media', '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 {
    browser: '浏览器',
    flow: '流程',
    human: '人工交互',
    keyboard: '键盘',
    media: '媒体',
    mouse: '鼠标',
    program: '程序',
    research: '研究',
    screen: '屏幕',
    text: '文本',
    vision: '视觉 AI',
    wait: '等待',
  }[category] || category
}

function nodeDefinition(nodeType) {
  return nodeDefinitions.value.find((item) => item.type === nodeType)
}

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)
  refreshEdgeLabels()
}

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 || {}),
      collapsed: false,
    },
  }
}

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: '',
    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: {},
      collapsed: false,
    },
  }
  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: '',
    data: { kind },
    animated: true,
    style: { stroke: '#2563eb' },
  })
  refreshEdgeLabels()
}

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

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

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

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

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

function edgeSourcePort(edge) {
  return edge.sourceHandle || (edge.data?.kind === 'data' ? 'value' : 'success')
}

function edgeTargetPort(edge) {
  return edge.targetHandle || (edge.data?.kind === 'data' ? 'value' : 'run')
}

function edgeEndpointLabel(nodeId, port) {
  const node = flowNodes.value.find((item) => item.id === nodeId)
  const title = node?.data?.title || nodeId || '未知节点'
  return port ? `${title}.${port}` : title
}

function readableEdgeLabel(edge) {
  return `${edgeEndpointLabel(edge.source, edgeSourcePort(edge))} → ${edgeEndpointLabel(edge.target, edgeTargetPort(edge))}`
}

function refreshEdgeLabels() {
  flowEdges.value.forEach((edge) => {
    edge.label = readableEdgeLabel(edge)
  })
}

function toggleNodeCollapsed(nodeId) {
  const node = flowNodes.value.find((item) => item.id === nodeId)
  if (node) node.data.collapsed = !node.data.collapsed
}

function fieldEntries(fields = {}) {
  return Object.entries(fields).map(([key, field]) => ({
    key,
    label: field.label || key,
    type: field.type || 'any',
    description: field.description || '',
  }))
}

function nodeOutputEntries(nodeType) {
  return fieldEntries(nodeDefinition(nodeType)?.outputs || {})
}

function outputEntriesForNode(nodeId) {
  const node = flowNodes.value.find((item) => item.id === nodeId)
  return node ? nodeOutputEntries(node.data.nodeType) : []
}

function nodeParamEntries(data) {
  const definition = nodeDefinition(data.nodeType)
  const params = data.params || {}
  return fieldEntries(definition?.params || {})
    .filter((item) => params[item.key] !== undefined && params[item.key] !== '')
    .map((item) => ({ ...item, value: params[item.key] }))
}

function nodeInputEntries(data) {
  const definition = nodeDefinition(data.nodeType)
  const inputs = data.inputs || {}
  return fieldEntries(definition?.inputs || {})
    .filter((item) => inputs[item.key])
    .map((item) => ({ ...item, binding: inputs[item.key] }))
}

function shortValue(value) {
  if (value === null || value === undefined || value === '') return '空'
  if (typeof value === 'boolean') return value ? '是' : '否'
  if (typeof value === 'object') {
    const text = JSON.stringify(value)
    return text.length > 28 ? `${text.slice(0, 28)}...` : text
  }
  const text = String(value)
  return text.length > 28 ? `${text.slice(0, 28)}...` : text
}

function bindingSummary(binding) {
  if (!binding) return '未设置'
  if (binding.source === 'variable') return `变量:${binding.name || '-'}`
  if (binding.source === 'node_output') return `${edgeEndpointLabel(binding.node_id, binding.output || '-')}`
  if (binding.source === 'runtime') return `运行时:${binding.name || '-'}`
  return shortValue(binding.value)
}

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 {}
}

function variableJsonText(value) {
  return JSON.stringify(value ?? {}, null, 2)
}

function updateVariableJson(name, value) {
  try {
    ensureVariableObject(name).default = JSON.parse(value)
  } catch {
    ElMessage.error(`变量 ${name} 的默认值不是有效 JSON`)
  }
}

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 || !workflowKey.value.trim()) {
    ElMessage.warning('请先保存并设置 workflow key')
    return
  }
  running.value = true
  try {
    const { data } = await api.post(`/api/automation/workflows/by-key/${encodeURIComponent(workflowKey.value.trim())}/run`, {})
    runOutput.value = JSON.stringify(data, null, 2)
    ElMessage.success('任务已加入执行队列')
    emit('task-created', data)
  } catch (error) {
    ElMessage.error(error.response?.data?.detail || '执行工作流失败')
  } finally {
    running.value = false
  }
}

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