import { ref, reactive } from 'vue'
import { useMessage } from 'naive-ui'
import { runWorkflow } from '../api/workflow'

/**
 * 判断对象是否为节点输出 envelope `{status, message, data}`。
 * 旧版直接输出 Map 的记录没有 status/data 字段，返回 false 以走兼容分支。
 */
export function isEnvelope(o) {
  return !!(o && typeof o === 'object' && 'status' in o && 'data' in o)
}

/**
 * 解包节点输出：envelope 返回 data，否则原样返回。
 * 兜底 data 缺失时返回空对象，避免下游 v-for 报错。
 */
export function unwrapNodeOutput(o) {
  return isEnvelope(o) ? (o.data || {}) : (o || {})
}

/**
 * 获取节点输出 envelope.status（200=成功，400=失败）。
 * 非 envelope 返回 null（视为成功）。
 */
export function nodeOutputStatus(o) {
  return isEnvelope(o) ? o.status : null
}

/**
 * 获取节点输出 envelope.message（含失败原因、重试次数等提示）。
 * 非 envelope 返回空串。
 */
export function nodeOutputMessage(o) {
  return isEnvelope(o) ? (o.message || '') : ''
}

/**
 * 工作流运行时 composable
 * 抽取自 WorkflowEditor.vue，承担 SSE 流解析、节点状态更新、运行结果管理
 *
 * @param {Object} options
 * @param {import('vue').Ref} options.getNodes 画布节点（用于按 nodeId 找节点 + 设置 class）
 * @param {Object} options.nodeTypeInfo 节点类型 → { color, typeLabel } 映射
 * @param {import('vue').Ref} options.workflowIdRef 当前工作流 name 或 id（仅用于 lastRunWorkflowId 记录）
 */
export function useWorkflowRunner({ getNodes, nodeTypeInfo, workflowIdRef }) {
  const message = useMessage()

  const running = ref(false)
  const showRunDialog = ref(false)
  const showResult = ref(false)
  const workflowResult = ref(null)
  const nodeStatuses = reactive({})
  const activeTab = ref('props')
  const nodeResults = reactive([])
  const expandedLogs = reactive({})
  const expandedContext = reactive({})
  // 思考过程折叠状态：key=nodeId，value=true/false。未设置默认展开。
  // 折叠时仅隐藏 UI，streamingThinking 仍持续累加，展开后可继续看到完整内容。
  const expandedThinking = reactive({})
  const lastRunId = ref(null)
  const lastRunWorkflowId = ref(null)

  function resetState() {
    Object.keys(nodeStatuses).forEach(k => delete nodeStatuses[k])
    nodeResults.splice(0, nodeResults.length)
  }

  function clearNodeStatusClasses() {
    getNodes.value.forEach(n => { n.class = '' })
  }

  /**
   * 启动工作流运行
   * @param {string|number} nameOrId 工作流 name（kebab-case）或旧数字 id
   * @param {Object} inputs 表单输入值
   * @param {Array<{file:File, relativePath:string}>} uploadFiles 上传文件列表
   */
  async function startRun(nameOrId, inputs, uploadFiles) {
    showRunDialog.value = false
    running.value = true
    showResult.value = false
    workflowResult.value = null
    resetState()
    clearNodeStatusClasses()
    // 清空折叠状态（不影响本轮首次默认展开）
    Object.keys(expandedThinking).forEach(k => delete expandedThinking[k])
    // 启动时单次切到「执行结果」Tab；后续不再强制切换，允许用户自由回到「节点属性」
    activeTab.value = 'result'

    try {
      const response = await runWorkflow(
        nameOrId,
        inputs,
        uploadFiles.map(f => f.file),
        uploadFiles.map(f => f.relativePath)
      )
      if (!response.ok) throw new Error(`HTTP ${response.status}`)

      const reader = response.body.getReader()
      const decoder = new TextDecoder()
      let buffer = ''

      while (true) {
        const { done, value } = await reader.read()
        if (done) break

        buffer += decoder.decode(value, { stream: true })
        const parts = buffer.split('\n\n')
        buffer = parts.pop()

        for (const part of parts) {
          const lines = part.split('\n')
          let data = null
          for (const line of lines) {
            if (line.startsWith('data:')) {
              try { data = JSON.parse(line.substring(5).trim()) } catch { /* skip */ }
            }
          }
          if (data) handleSSEEvent(data)
        }
      }
    } catch (e) {
      message.error('工作流执行失败: ' + e.message)
    } finally {
      running.value = false
    }
  }

  function handleSSEEvent(event) {
    if (event.type === 'node_status' && event.nodeId) {
      const status = event.status?.toLowerCase() || 'running'
      nodeStatuses[event.nodeId] = status
      const node = getNodes.value.find(n => n.id === event.nodeId)
      if (node) node.class = `node-status-${status}`

      const info = nodeTypeInfo[node?.type] || { color: '#666', typeLabel: '未知' }
      const existing = nodeResults.find(r => r.nodeId === event.nodeId)
      const update = {
        nodeId: event.nodeId,
        type: node?.type,
        label: node?.data?.label || '节点',
        status,
        output: event.output || existing?.output,
        // 过滤掉 THINKING 类型日志：思考过程已通过 streamingThinking 单独聚合展示，
        // 列表中再显示会造成内容重复（流式 token 拼接的多条 message 与完整思考重复）
        logs: filterNonThinkingLogs(event.logs) || existing?.logs || [],
        // 节点执行后的完整 variables 快照（仅 SUCCESS 时由后端携带），用于 debug 视图
        contextSnapshot: event.contextSnapshot || existing?.contextSnapshot || null,
        // 保留此前累加的流式 thinking 内容（节点完成后仍可见思考历史）
        streamingThinking: existing?.streamingThinking || '',
        color: info.color,
        typeLabel: info.typeLabel
      }
      if (existing) {
        Object.assign(existing, update)
      } else {
        nodeResults.push(update)
      }
    } else if (event.type === 'node_stream' && event.nodeId) {
      // 节点执行过程中的流式增量（Hermes Agent 的 thinking 等）
      // thinking 内容按 nodeId 聚合累加，不产生独立条目
      if (event.kind === 'thinking') {
        const delta = event.content || ''
        if (!delta) return
        const existing = nodeResults.find(r => r.nodeId === event.nodeId)
        if (existing) {
          existing.streamingThinking = (existing.streamingThinking || '') + delta
        } else {
          const node = getNodes.value.find(n => n.id === event.nodeId)
          const info = nodeTypeInfo[node?.type] || { color: '#666', typeLabel: '未知' }
          nodeResults.push({
            nodeId: event.nodeId,
            type: node?.type,
            label: node?.data?.label || '节点',
            status: 'running',
            streamingThinking: delta,
            color: info.color,
            typeLabel: info.typeLabel
          })
        }
        // 注意：不在此处切换 activeTab，避免流式输出过程中锁定 UI 不让用户回到「节点属性」
      }
      // tool_call / tool_result 已通过节点完成后的 logs 显示，此处无需重复处理
    } else if (event.type === 'workflow_complete') {
      workflowResult.value = event.output
      showResult.value = true
      if (event.output?._runId) {
        lastRunId.value = event.output._runId
        lastRunWorkflowId.value = workflowIdRef.value
      } else if (event.runId) {
        lastRunId.value = event.runId
        lastRunWorkflowId.value = workflowIdRef.value
      }
      message.success('工作流执行完成')
    } else if (event.type === 'workflow_error') {
      message.error('执行失败: ' + (event.error || '未知错误'))
    }
  }

  function closeResult() {
    showResult.value = false
    resetState()
    Object.keys(expandedLogs).forEach(k => delete expandedLogs[k])
    clearNodeStatusClasses()
    activeTab.value = 'props'
  }

  function openRunDialog(inputFields, formData) {
    Object.keys(formData).forEach(k => delete formData[k])
    inputFields.value.forEach(f => { formData[f.name] = '' })
    showRunDialog.value = true
  }

  function cancelRun() {
    showRunDialog.value = false
  }

  function statusText(s) {
    return { running: '执行中', success: '成功', failed: '失败', skipped: '跳过', no_run: '未运行' }[s] || s
  }

  function logTypeIcon(type) {
    return { TOOL_CALL: '🔧', TOOL_RESULT: '📋', THINKING: '💭', ERROR: '❌', INFO: 'ℹ️' }[type] || '•'
  }

  function logTypeLabel(type) {
    return { TOOL_CALL: '调用工具', TOOL_RESULT: '工具返回', THINKING: '思考', ERROR: '错误', INFO: '信息' }[type] || type
  }

  function formatTimestamp(ts) {
    if (!ts) return ''
    const d = new Date(ts)
    return d.toLocaleTimeString('zh-CN', { hour12: false })
  }

  /**
   * 过滤掉 THINKING 类型日志。
   * 思考过程已通过 streamingThinking 单独聚合展示，日志列表中再显示会造成内容重复。
   */
  function filterNonThinkingLogs(logs) {
    if (!Array.isArray(logs)) return logs
    return logs.filter(l => l.type !== 'THINKING')
  }

  function toggleLogs(nodeId) {
    expandedLogs[nodeId] = !expandedLogs[nodeId]
  }

  function toggleContext(nodeId) {
    expandedContext[nodeId] = !expandedContext[nodeId]
  }

  function toggleThinking(nodeId) {
    expandedThinking[nodeId] = !expandedThinking[nodeId]
  }

  /**
   * 格式化 contextSnapshot 中的值：
   * - 对象/数组：JSON.stringify（缩进 2）
   * - 字符串：原样返回，超长由 CSS 控制最大高度
   * - 其他：String(value)
   */
  function formatContextValue(value) {
    if (value === null || value === undefined) return 'null'
    if (typeof value === 'object') return JSON.stringify(value, null, 2)
    return String(value)
  }

  return {
    running,
    showRunDialog,
    showResult,
    workflowResult,
    nodeStatuses,
    activeTab,
    nodeResults,
    expandedLogs,
    expandedContext,
    expandedThinking,
    lastRunId,
    lastRunWorkflowId,
    startRun,
    openRunDialog,
    cancelRun,
    closeResult,
    statusText,
    logTypeIcon,
    logTypeLabel,
    formatTimestamp,
    toggleLogs,
    toggleContext,
    toggleThinking,
    formatContextValue
  }
}
