<template>
  <div class="ivr-flow">
    <div class="flow-layout">
      <!-- Left sidebar: flow list + node palette -->
      <div class="left-panel">
        <div class="panel-section flow-list">
          <div class="section-header">
            <span class="section-title">流程列表</span>
            <el-button type="primary" size="small" @click="createNewFlow">新建</el-button>
          </div>
          <el-table
            :data="flows"
            highlight-current-row
            size="small"
            @row-click="handleFlowRowClick"
          >
            <el-table-column prop="flowCode" label="编码" show-overflow-tooltip />
            <el-table-column prop="flowName" label="名称" show-overflow-tooltip />
            <el-table-column prop="status" label="状态" width="70">
              <template #default="scope">
                <el-tag :type="statusTagType(scope.row.status)" size="small">
                  {{ statusText(scope.row.status) }}
                </el-tag>
              </template>
            </el-table-column>
            <el-table-column prop="version" label="版本" width="55">
              <template #default="scope">
                <span>v{{ scope.row.version || 1 }}</span>
              </template>
            </el-table-column>
          </el-table>
        </div>

        <div class="panel-section node-palette">
          <div class="section-header">
            <span class="section-title">节点组件</span>
          </div>
          <div class="palette-grid">
            <div
              v-for="item in paletteNodes"
              :key="item.type"
              class="palette-item"
              :class="`palette-${item.type}`"
              draggable
              @click="addNode(item.type)"
              @dragstart="onDragStart($event, item.type)"
            >
              {{ item.label }}
            </div>
          </div>
        </div>
      </div>

      <!-- Center canvas -->
      <div class="canvas-area" @drop="onDrop" @dragover="onDragOver">
        <div class="flow-toolbar">
          <el-input
            v-model="form.flowCode"
            placeholder="流程编码"
            style="width: 160px"
            :disabled="isEdit"
          />
          <el-input
            v-model="form.flowName"
            placeholder="流程名称"
            style="width: 180px"
          />
          <el-button type="primary" @click="handleSave">保存</el-button>
          <el-button type="success" @click="handlePublish">发布</el-button>
          <el-button type="warning" @click="handleOffline">下线</el-button>
          <el-button type="danger" @click="handleDelete">删除</el-button>
          <el-button @click="resetCanvas">清空画布</el-button>
        </div>

        <div class="flow-canvas">
          <VueFlow
            v-model="elements"
            fit-view-on-init
            :default-zoom="1"
            @node-click="onNodeClick"
            @edge-click="onEdgeClick"
            @pane-click="onPaneClick"
          >
            <Background pattern-color="#aaa" :gap="16" />
            <Controls />
            <template #node-flowNode="nodeProps">
              <div
                class="flow-node"
                :class="[
                  `node-${nodeProps.data.nodeType}`,
                  { 'node-selected': nodeProps.selected },
                ]"
              >
                <Handle type="target" :position="Position.Top" />
                <div class="node-icon">{{ nodeTypeIcon(nodeProps.data.nodeType) }}</div>
                <div class="node-label">{{ nodeProps.label }}</div>
                <Handle type="source" :position="Position.Bottom" />
              </div>
            </template>
          </VueFlow>
        </div>
      </div>

      <!-- Right config panel -->
      <div v-if="selectedNode || selectedEdge" class="right-panel">
        <template v-if="selectedNode">
          <div class="section-header">
            <span class="section-title">节点配置</span>
            <span class="node-type-tag">{{ nodeTypeLabel(selectedNode.data.nodeType) }}</span>
          </div>

          <el-form label-width="90px" class="config-form">
            <!-- start -->
            <template v-if="selectedNode.data.nodeType === 'start'">
              <el-form-item label="触发类型">
                <el-select v-model="selectedNode.data.config.triggerType" style="width: 100%">
                  <el-option label="呼入电话" value="inbound_call" />
                  <el-option label="外呼触发" value="outbound_call" />
                </el-select>
              </el-form-item>
              <el-form-item label="电话号码">
                <el-input v-model="selectedNode.data.config.phoneNumber" placeholder="接入号码/外呼号码" />
              </el-form-item>
            </template>

            <!-- play -->
            <template v-if="selectedNode.data.nodeType === 'play'">
              <el-form-item label="播放类型">
                <el-select v-model="selectedNode.data.config.playType" style="width: 100%">
                  <el-option label="音频文件" value="audio" />
                  <el-option label="TTS 文本" value="tts" />
                </el-select>
              </el-form-item>
              <el-form-item label="音频 URL" v-if="selectedNode.data.config.playType === 'audio'">
                <el-input v-model="selectedNode.data.config.audioUrl" placeholder="https://" />
              </el-form-item>
              <el-form-item label="TTS 文本" v-if="selectedNode.data.config.playType === 'tts'">
                <el-input
                  v-model="selectedNode.data.config.ttsText"
                  type="textarea"
                  :rows="4"
                  placeholder="请输入语音播报文本"
                />
              </el-form-item>
            </template>

            <!-- menu -->
            <template v-if="selectedNode.data.nodeType === 'menu'">
              <el-form-item label="播报提示">
                <el-input
                  v-model="selectedNode.data.config.prompt"
                  type="textarea"
                  :rows="3"
                  placeholder="请输入按键菜单播报内容"
                />
              </el-form-item>
              <el-form-item label="超时时间">
                <el-input-number v-model="selectedNode.data.config.timeout" :min="1" :max="60" style="width: 100%" />
              </el-form-item>
              <el-form-item label="按键选项">
                <div class="menu-options">
                  <div v-for="(opt, index) in selectedNode.data.config.options" :key="index" class="menu-option-row">
                    <el-input v-model="opt.key" placeholder="键" style="width: 60px" />
                    <el-input v-model="opt.label" placeholder="描述" style="flex: 1" />
                    <el-button type="danger" link size="small" @click="removeMenuOption(index)">删除</el-button>
                  </div>
                  <el-button type="primary" link size="small" @click="addMenuOption">+ 添加选项</el-button>
                </div>
              </el-form-item>
            </template>

            <!-- transfer -->
            <template v-if="selectedNode.data.nodeType === 'transfer'">
              <el-form-item label="转接号码">
                <el-input v-model="selectedNode.data.config.destination" placeholder="坐席/队列号码" />
              </el-form-item>
            </template>

            <!-- hangup -->
            <template v-if="selectedNode.data.nodeType === 'hangup'">
              <el-form-item label="挂断原因">
                <el-input v-model="selectedNode.data.config.reason" placeholder="正常结束" />
              </el-form-item>
            </template>

            <!-- api -->
            <template v-if="selectedNode.data.nodeType === 'api'">
              <el-form-item label="请求地址">
                <el-input v-model="selectedNode.data.config.url" placeholder="https://" />
              </el-form-item>
              <el-form-item label="请求方法">
                <el-select v-model="selectedNode.data.config.method" style="width: 100%">
                  <el-option label="POST" value="POST" />
                  <el-option label="GET" value="GET" />
                  <el-option label="PUT" value="PUT" />
                </el-select>
              </el-form-item>
              <el-form-item label="请求体模板">
                <el-input
                  v-model="selectedNode.data.config.bodyTemplate"
                  type="textarea"
                  :rows="6"
                  placeholder='{"phone":"{{phone}}"}'
                />
              </el-form-item>
            </template>
          </el-form>
        </template>

        <template v-if="selectedEdge">
          <div class="section-header">
            <span class="section-title">边配置</span>
          </div>
          <el-form label-width="80px" class="config-form">
            <el-form-item label="标签">
              <el-input v-model="selectedEdge.label" placeholder="分支标签，如 1 / 2 / default" />
            </el-form-item>
          </el-form>
        </template>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { onMounted, reactive, ref } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { VueFlow, Handle, Position, useVueFlow } from '@vue-flow/core'
import { Background } from '@vue-flow/background'
import { Controls } from '@vue-flow/controls'
import {
  listFlows,
  getFlow,
  saveFlow,
  updateFlow,
  publishFlow,
  offlineFlow,
  deleteFlow,
} from '@/api/ivrFlow'
import '@vue-flow/core/dist/style.css'
import '@vue-flow/core/dist/theme-default.css'

const { project } = useVueFlow()

interface FlowForm {
  flowCode: string
  flowName: string
}

const form = reactive<FlowForm>({
  flowCode: '',
  flowName: '',
})

const flows = ref<any[]>([])
const elements = ref<any[]>([])
const selectedNode = ref<any>(null)
const selectedEdge = ref<any>(null)
const isEdit = ref(false)

const paletteNodes = [
  { type: 'start', label: '开始' },
  { type: 'play', label: '播放语音' },
  { type: 'menu', label: '按键菜单' },
  { type: 'transfer', label: '转人工' },
  { type: 'hangup', label: '挂断' },
  { type: 'api', label: 'API 调用' },
]

const defaultMenuOptions = () => [
  { key: '1', label: '' },
  { key: '2', label: '' },
]

const nodeTypeConfig: Record<string, () => any> = {
  start: () => ({ triggerType: 'inbound_call', phoneNumber: '' }),
  play: () => ({ playType: 'audio', audioUrl: '', ttsText: '' }),
  menu: () => ({ prompt: '', timeout: 10, options: defaultMenuOptions() }),
  transfer: () => ({ destination: '' }),
  hangup: () => ({ reason: '' }),
  api: () => ({ url: '', method: 'POST', bodyTemplate: '' }),
}

const nodeTypeLabels: Record<string, string> = {
  start: '开始',
  play: '播放语音',
  menu: '按键菜单',
  transfer: '转人工',
  hangup: '挂断',
  api: 'API 调用',
}

const nodeTypeIcons: Record<string, string> = {
  start: '▶',
  play: '🔊',
  menu: '⌨',
  transfer: '📞',
  hangup: '⏹',
  api: '⚡',
}

function nodeTypeLabel(type: string) {
  return nodeTypeLabels[type] || type
}

function nodeTypeIcon(type: string) {
  return nodeTypeIcons[type] || '•'
}

function statusText(status: number) {
  if (status === 1) return '已发布'
  if (status === 2) return '已下线'
  return '草稿'
}

function statusTagType(status: number) {
  if (status === 1) return 'success'
  if (status === 2) return 'warning'
  return 'info'
}

function createNodeId() {
  return `node_${Date.now()}_${Math.floor(Math.random() * 1000)}`
}

function createEdgeId(source: string, target: string) {
  return `e_${source}_${target}`
}

function getDefaultPosition() {
  const count = elements.value.filter((el) => !('source' in el)).length
  const row = Math.floor(count / 2)
  const col = count % 2
  return { x: 200 + col * 220, y: 80 + row * 140 }
}

function addNode(type: string, position?: { x: number; y: number }) {
  const id = createNodeId()
  const config = nodeTypeConfig[type]()
  elements.value.push({
    id,
    type: 'flowNode',
    label: nodeTypeLabels[type],
    position: position || getDefaultPosition(),
    data: { nodeType: type, config },
  })
}

function addMenuOption() {
  if (!selectedNode.value) return
  const options = selectedNode.value.data.config.options
  options.push({ key: String(options.length + 1), label: '' })
}

function removeMenuOption(index: number | string) {
  if (!selectedNode.value) return
  selectedNode.value.data.config.options.splice(Number(index), 1)
}

function onDragStart(event: DragEvent, type: string) {
  if (event.dataTransfer) {
    event.dataTransfer.setData('application/vueflow-node', type)
    event.dataTransfer.effectAllowed = 'move'
  }
}

function onDragOver(event: DragEvent) {
  event.preventDefault()
  if (event.dataTransfer) {
    event.dataTransfer.dropEffect = 'move'
  }
}

function onDrop(event: DragEvent) {
  event.preventDefault()
  if (!event.dataTransfer) return
  const type = event.dataTransfer.getData('application/vueflow-node')
  if (!type) return

  const bounds = (event.currentTarget as HTMLElement).getBoundingClientRect()
  const position = project({
    x: event.clientX - bounds.left,
    y: event.clientY - bounds.top,
  })
  addNode(type, position)
}

function onNodeClick(event: any) {
  const node = event.node
  selectedEdge.value = null
  const found = elements.value.find((el) => el.id === node.id)
  selectedNode.value = found || node
}

function onEdgeClick(event: any) {
  const edge = event.edge
  selectedNode.value = null
  const found = elements.value.find((el) => el.id === edge.id)
  selectedEdge.value = found || edge
}

function onPaneClick() {
  selectedNode.value = null
  selectedEdge.value = null
}

function resetCanvas() {
  elements.value = []
  form.flowCode = ''
  form.flowName = ''
  isEdit.value = false
  selectedNode.value = null
  selectedEdge.value = null
}

function createNewFlow() {
  resetCanvas()
  form.flowCode = `ivr_${Date.now()}`
  form.flowName = '新建 IVR 流程'
  addNode('start')
  addNode('play')
}

function handleFlowRowClick(row: any) {
  loadFlow(row.flowCode)
}

function parseDefinitionJson(row: any): { nodes: any[]; edges: any[] } {
  if (!row.definitionJson) return { nodes: [], edges: [] }
  if (typeof row.definitionJson === 'string') {
    try {
      return JSON.parse(row.definitionJson)
    } catch {
      return { nodes: [], edges: [] }
    }
  }
  return row.definitionJson
}

async function loadFlow(flowCode: string) {
  try {
    const res: any = await getFlow(flowCode)
    const row = res.data
    if (!row) {
      ElMessage.warning('流程不存在')
      return
    }

    form.flowCode = row.flowCode
    form.flowName = row.flowName
    isEdit.value = true

    const definition = parseDefinitionJson(row)
    const nodes = (definition.nodes || []).map((n: any, index: number) => {
      const type = n.type || n.nodeType || 'start'
      const config = n.config || nodeTypeConfig[type]()
      return {
        id: n.id || createNodeId(),
        type: 'flowNode',
        label: nodeTypeLabels[type] || type,
        position: n.position || {
          x: 200 + (index % 3) * 220,
          y: 80 + Math.floor(index / 3) * 140,
        },
        data: { nodeType: type, config },
      }
    })

    const nodeIds = new Set(nodes.map((n) => n.id))
    const edges = (definition.edges || [])
      .filter((e: any) => nodeIds.has(e.source) && nodeIds.has(e.target))
      .map((e: any) => ({
        id: e.id || createEdgeId(e.source, e.target),
        source: e.source,
        target: e.target,
        label: e.label,
      }))

    elements.value = [...nodes, ...edges]
    selectedNode.value = null
    selectedEdge.value = null
  } catch (e: any) {
    ElMessage.error(e.message)
  }
}

async function loadFlows() {
  try {
    const res: any = await listFlows()
    flows.value = res.data || []
  } catch (e: any) {
    ElMessage.error(e.message)
  }
}

function buildPayload() {
  const nodes = elements.value
    .filter((el) => !('source' in el))
    .map((el) => ({
      id: el.id,
      type: el.data?.nodeType,
      config: el.data?.config || {},
      position: el.position,
    }))

  const edges = elements.value
    .filter((el) => 'source' in el)
    .map((el) => ({
      source: el.source,
      target: el.target,
      label: el.label,
    }))

  return {
    flowCode: form.flowCode,
    flowName: form.flowName,
    flowType: 'ivr',
    definitionJson: { nodes, edges },
  }
}

async function handleSave() {
  if (!form.flowCode.trim()) {
    ElMessage.warning('请输入流程编码')
    return
  }
  if (!form.flowName.trim()) {
    ElMessage.warning('请输入流程名称')
    return
  }

  try {
    const payload = buildPayload()
    if (isEdit.value) {
      await updateFlow(form.flowCode, payload)
      ElMessage.success('更新成功')
    } else {
      await saveFlow(payload)
      ElMessage.success('保存成功')
      isEdit.value = true
    }
    await loadFlows()
  } catch (e: any) {
    ElMessage.error(e.message)
  }
}

async function handlePublish() {
  if (!form.flowCode.trim()) {
    ElMessage.warning('请先选择或保存流程')
    return
  }
  try {
    await publishFlow(form.flowCode)
    ElMessage.success('发布成功')
    await loadFlows()
  } catch (e: any) {
    ElMessage.error(e.message)
  }
}

async function handleOffline() {
  if (!form.flowCode.trim()) {
    ElMessage.warning('请先选择流程')
    return
  }
  try {
    await offlineFlow(form.flowCode)
    ElMessage.success('已下线')
    await loadFlows()
  } catch (e: any) {
    ElMessage.error(e.message)
  }
}

async function handleDelete() {
  if (!form.flowCode.trim()) {
    ElMessage.warning('请先选择流程')
    return
  }
  try {
    await ElMessageBox.confirm(`确定删除流程 ${form.flowCode} 吗？`, '提示', { type: 'warning' })
    await deleteFlow(form.flowCode)
    ElMessage.success('删除成功')
    resetCanvas()
    await loadFlows()
  } catch (e: any) {
    if (e !== 'cancel') {
      ElMessage.error(e.message)
    }
  }
}

onMounted(() => {
  loadFlows()
})
</script>

<style scoped>
.ivr-flow {
  height: calc(100vh - 120px);
  display: flex;
  flex-direction: column;
}

.flow-layout {
  display: flex;
  flex: 1;
  gap: 12px;
  min-height: 0;
}

.left-panel {
  width: 260px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-height: 0;
}

.panel-section {
  background: #fff;
  border: 1px solid #e4e7ed;
  border-radius: 4px;
  padding: 12px;
  overflow: auto;
}

.flow-list {
  flex: 1;
  min-height: 0;
}

.node-palette {
  flex-shrink: 0;
}

.section-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 12px;
}

.section-title {
  font-weight: 500;
  font-size: 14px;
}

.palette-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}

.palette-item {
  padding: 10px 8px;
  border: 1px solid #dcdfe6;
  border-radius: 4px;
  text-align: center;
  font-size: 13px;
  cursor: pointer;
  transition: all 0.2s;
  user-select: none;
}

.palette-item:hover {
  border-color: #409eff;
  color: #409eff;
  background: #ecf5ff;
}

.canvas-area {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
  border: 1px solid #e4e7ed;
  border-radius: 4px;
  background: #fff;
}

.flow-toolbar {
  padding: 12px;
  border-bottom: 1px solid #e4e7ed;
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.flow-canvas {
  flex: 1;
  min-height: 0;
}

.right-panel {
  width: 320px;
  background: #fff;
  border: 1px solid #e4e7ed;
  border-radius: 4px;
  padding: 12px;
  overflow: auto;
}

.config-form {
  margin-top: 12px;
}

.node-type-tag {
  font-size: 12px;
  color: #409eff;
  background: #ecf5ff;
  padding: 2px 8px;
  border-radius: 4px;
}

.menu-options {
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: 100%;
}

.menu-option-row {
  display: flex;
  align-items: center;
  gap: 8px;
}

.flow-node {
  padding: 10px 16px;
  border-radius: 6px;
  border: 1px solid #dcdfe6;
  background: #fff;
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 110px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.06);
}

.flow-node.node-selected {
  border-color: #409eff;
  box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
}

.node-icon {
  font-size: 16px;
}

.node-label {
  font-size: 13px;
  font-weight: 500;
}

.node-start {
  border-left: 4px solid #67c23a;
}

.node-play {
  border-left: 4px solid #409eff;
}

.node-menu {
  border-left: 4px solid #e6a23c;
}

.node-transfer {
  border-left: 4px solid #f56c6c;
}

.node-hangup {
  border-left: 4px solid #909399;
}

.node-api {
  border-left: 4px solid #9254de;
}
</style>
