/**
 * Workflow Serializer - Convert between Vue Flow JSON and WorkflowDefinition
 *
 * Vue Flow uses nodes/edges model, while WorkflowDefinition uses stages with dependencies.
 * This module handles the bidirectional conversion.
 */

import type { Node, Edge } from '@vue-flow/core'

// ---------------------------------------------------------------------------
// Types matching backend WorkflowDefinition
// ---------------------------------------------------------------------------

export interface WorkflowStage {
  name: string
  agent: string
  action: string
  depends_on: string[]
  inputs: Record<string, unknown>
  outputs: string[]
  timeout_seconds: number
  retry_count: number
  continue_on_failure: boolean
  condition: string | null
  type: 'skill' | 'condition' | 'approval' | 'parallel'
  config: Record<string, unknown>
}

export interface WorkflowDefinition {
  workflow_id: string
  name: string
  version: number
  stages: WorkflowStage[]
  triggers: Record<string, unknown>[]
  variables_schema: Record<string, unknown>
  output_schema: Record<string, unknown>
  created_at: string
  updated_at: string
}

export interface WorkflowSummary {
  workflow_id: string
  name: string
  version: number
  stage_count: number
  trigger_count: number
  created_at: string
  updated_at: string
}

export interface WorkflowExecution {
  execution_id: string
  workflow_id: string
  status: 'pending' | 'running' | 'paused' | 'completed' | 'failed' | 'cancelled'
  current_stage: string | null
  stage_results: Record<string, unknown>
  started_at: string | null
  completed_at: string | null
  error: string | null
  variables: Record<string, unknown>
}

// ---------------------------------------------------------------------------
// Node data type for Vue Flow custom nodes
// ---------------------------------------------------------------------------

export interface WorkflowNodeData {
  label: string
  type: 'skill' | 'condition' | 'approval' | 'parallel'
  config: Record<string, unknown>
  action: string
  agent: string
  timeout_seconds: number
  retry_count: number
  condition: string | null
  [key: string]: unknown
}

// ---------------------------------------------------------------------------
// Default values for new nodes
// ---------------------------------------------------------------------------

const DEFAULT_NODE_DATA: Record<string, Partial<WorkflowNodeData>> = {
  skill: {
    label: '技能节点',
    type: 'skill',
    action: '',
    agent: 'default',
    timeout_seconds: 300,
    retry_count: 0,
    condition: null,
    config: {},
  },
  condition: {
    label: '条件节点',
    type: 'condition',
    action: 'evaluate',
    agent: 'default',
    timeout_seconds: 60,
    retry_count: 0,
    condition: null,
    config: { expression: '' },
  },
  approval: {
    label: '审批节点',
    type: 'approval',
    action: 'approve',
    agent: 'default',
    timeout_seconds: 3600,
    retry_count: 0,
    condition: null,
    config: { approver: '', timeout: 3600 },
  },
  parallel: {
    label: '并行节点',
    type: 'parallel',
    action: 'parallel',
    agent: 'default',
    timeout_seconds: 600,
    retry_count: 0,
    condition: null,
    config: { max_parallel: 5 },
  },
}

export function getDefaultNodeData(nodeType: string): WorkflowNodeData {
  const defaults = DEFAULT_NODE_DATA[nodeType] || DEFAULT_NODE_DATA.skill
  return { ...defaults } as WorkflowNodeData
}

// ---------------------------------------------------------------------------
// Vue Flow → WorkflowDefinition
// ---------------------------------------------------------------------------

export function flowToWorkflow(
  nodes: Node<WorkflowNodeData>[],
  edges: Edge[],
  name: string,
  workflowId: string = '',
): WorkflowDefinition {
  const stages: WorkflowStage[] = nodes.map((node) => {
    const data = node.data
    // Find dependencies from incoming edges
    const dependsOn = edges
      .filter((e) => e.target === node.id)
      .map((e) => {
        const sourceNode = nodes.find((n) => n.id === e.source)
        return sourceNode?.data?.label || e.source
      })

    return {
      name: data.label,
      agent: data.agent || 'default',
      action: data.action || '',
      depends_on: dependsOn,
      inputs: {},
      outputs: [],
      timeout_seconds: data.timeout_seconds || 300,
      retry_count: data.retry_count || 0,
      continue_on_failure: false,
      condition: data.condition || null,
      type: data.type,
      config: data.config || {},
    }
  })

  return {
    workflow_id: workflowId,
    name,
    version: 1,
    stages,
    triggers: [],
    variables_schema: {},
    output_schema: {},
    created_at: new Date().toISOString(),
    updated_at: new Date().toISOString(),
  }
}

// ---------------------------------------------------------------------------
// WorkflowDefinition → Vue Flow
// ---------------------------------------------------------------------------

export function workflowToFlow(
  workflow: WorkflowDefinition,
): { nodes: Node<WorkflowNodeData>[]; edges: Edge[] } {
  const nodeMap = new Map<string, string>() // stage name -> node id

  const nodes: Node<WorkflowNodeData>[] = workflow.stages.map((stage, index) => {
    const nodeId = `node-${index}`
    nodeMap.set(stage.name, nodeId)

    return {
      id: nodeId,
      type: stage.type === 'condition' ? 'condition' : stage.type === 'approval' ? 'approval' : 'skill',
      position: { x: 100 + index * 250, y: 200 },
      data: {
        label: stage.name,
        type: stage.type,
        config: stage.config,
        action: stage.action,
        agent: stage.agent,
        timeout_seconds: stage.timeout_seconds,
        retry_count: stage.retry_count,
        condition: stage.condition,
      },
    }
  })

  const edges: Edge[] = []
  for (const stage of workflow.stages) {
    const targetId = nodeMap.get(stage.name)
    if (!targetId) continue

    for (const dep of stage.depends_on) {
      const sourceId = nodeMap.get(dep)
      if (!sourceId) continue

      // For condition nodes, determine if this is a "yes" or "no" branch
      const sourceStage = workflow.stages.find((s) => s.name === dep)
      let sourceHandle = 'output'
      let targetHandle = 'input'

      if (sourceStage?.type === 'condition') {
        // Check if this target is in the "yes" or "no" branch based on config
        const branchIndex = sourceStage.config?.branch_targets
          ? (sourceStage.config.branch_targets as string[]).indexOf(stage.name)
          : -1
        sourceHandle = branchIndex === 0 ? 'yes' : branchIndex === 1 ? 'no' : 'output'
      }

      edges.push({
        id: `edge-${sourceId}-${targetId}`,
        source: sourceId,
        target: targetId,
        sourceHandle,
        targetHandle,
        animated: true,
      })
    }
  }

  return { nodes, edges }
}
