/**
 * 审批流程状态映射工具
 * 
 * 负责将后端返回的审批历史数据映射为前端显示状态
 * 
 * 核心逻辑：
 * 1. 节点状态（NodeStatus）只表示执行状态，不表示业务结果
 * 2. 操作类型（ApprovalAction）决定业务结果（通过/拒绝/退回等）
 * 3. 需要综合节点状态和操作类型来判断最终的显示状态
 */

import type {
  HistoryItem,
  ActionLogItem,
  NodeStatusMapping,
  NodeDisplayStatus,
  ApprovalActionType,
  ApprovalAction,
  ActionDisplayMeta,
  ActionMetadataMap,
  ProcessModel,
  InstanceStatus,
  UserInfo,
} from '@/types/approval';
import { ApprovalActionType as ActionType } from '@/types/approval';

// ==================== 操作元数据映射表 ====================

/**
 * 操作类型元数据映射表
 * 
 * 定义每种操作类型的显示规则：
 * - icon: 图标（Unicode 或 Emoji）
 * - iconColor: 图标颜色（Tailwind 类名）
 * - label: 显示标签（国际化 key）
 * - labelColor: 标签颜色（Tailwind 类名）
 * - showInTimeline: 是否在主时间线显示
 * - requiresTargetUser: 是否需要目标用户信息
 * - requiresComment: 是否必须填写备注
 * - isAdminAction: 是否为管理员操作
 * - isAutoAction: 是否为自动操作
 * - priority: 优先级（数字越大优先级越高，用于多操作排序）
 * 
 * 优先级说明：
 * - 100: 系统异常（FAILED）
 * - 90: 管理员强制终止（ADMIN_TERMINATE）
 * - 80: 拒绝类（REJECT, ADMIN_REJECT, AUTO_REJECT）
 * - 70: 退回（RETURN）
 * - 60: 通过类（APPROVE, ADMIN_APPROVE, AUTO_APPROVE）
 * - 50: 流程控制（FORWARD, ADD_SIGN, DELEGATE, ADMIN_REASSIGN）
 * - 40: 辅助操作（CLAIM, ESCALATE）
 * - 30: 不显示在时间线（REMIND, COMMENT）
 */
export const ACTION_METADATA: ActionMetadataMap = {
  // ==================== 常规审批操作 ====================
  SUBMIT: {
    icon: '✓',
    iconColor: 'text-green-600',
    label: 'actions.SUBMIT',
    labelColor: 'bg-green-100 text-green-700',
    showInTimeline: true,
    requiresTargetUser: false,
    requiresComment: false,
    isAdminAction: false,
    isAutoAction: false,
    priority: 60,
  },
  APPROVE: {
    icon: '✓',
    iconColor: 'text-green-600',
    label: 'actions.APPROVE',
    labelColor: 'bg-green-100 text-green-700',
    showInTimeline: true,
    requiresTargetUser: false,
    requiresComment: false,
    isAdminAction: false,
    isAutoAction: false,
    priority: 60,
  },
  REJECT: {
    icon: '✗',
    iconColor: 'text-red-600',
    label: 'actions.REJECT',
    labelColor: 'bg-red-100 text-red-700',
    showInTimeline: true,
    requiresTargetUser: false,
    requiresComment: true,
    isAdminAction: false,
    isAutoAction: false,
    priority: 80,
  },
  RETURN: {
    icon: '↩',
    iconColor: 'text-orange-600',
    label: 'actions.RETURN',
    labelColor: 'bg-orange-100 text-orange-700',
    showInTimeline: true,
    requiresTargetUser: false,
    requiresComment: true,
    isAdminAction: false,
    isAutoAction: false,
    priority: 70,
  },
  WITHDRAW: {
    icon: '⊘',
    iconColor: 'text-gray-600',
    label: 'actions.WITHDRAW',
    labelColor: 'bg-gray-100 text-gray-600',
    showInTimeline: true,
    requiresTargetUser: false,
    requiresComment: false,  // ⭐ 撤回原因可选（符合业界标准）
    isAdminAction: false,
    isAutoAction: false,
    priority: 60,
  },
  
  // ==================== 流程控制操作 ====================
  FORWARD: {
    icon: '→',
    iconColor: 'text-blue-600',
    label: 'actions.FORWARD',
    labelColor: 'bg-blue-100 text-blue-700',
    showInTimeline: true,
    requiresTargetUser: true,
    requiresComment: false,
    isAdminAction: false,
    isAutoAction: false,
    priority: 50,
  },
  APPROVER_WITHDRAW: {
    icon: '↩',
    iconColor: 'text-orange-600',
    label: 'actions.APPROVER_WITHDRAW',
    labelColor: 'bg-orange-100 text-orange-700',
    showInTimeline: true,
    requiresTargetUser: false,
    requiresComment: true,
    isAdminAction: false,
    isAutoAction: false,
    priority: 50,
  },
  ADD_SIGN: {
    icon: '+',
    iconColor: 'text-blue-600',
    label: 'actions.ADD_SIGN',
    labelColor: 'bg-blue-100 text-blue-700',
    showInTimeline: true,
    requiresTargetUser: true,
    requiresComment: false,
    isAdminAction: false,
    isAutoAction: false,
    priority: 50,
  },
  DELEGATE: {
    icon: '⇄',
    iconColor: 'text-blue-600',
    label: 'actions.DELEGATE',
    labelColor: 'bg-blue-100 text-blue-700',
    showInTimeline: true,
    requiresTargetUser: true,
    requiresComment: false,
    isAdminAction: false,
    isAutoAction: false,
    priority: 50,
  },
  ESCALATE: {
    icon: '⬆',
    iconColor: 'text-orange-600',
    label: 'actions.ESCALATE',
    labelColor: 'bg-orange-100 text-orange-700',
    showInTimeline: true,
    requiresTargetUser: true,
    requiresComment: false,
    isAdminAction: false,
    isAutoAction: true,  // ⭐ 系统自动升级（按文档规范修正）
    priority: 40,
  },
  
  // ==================== 自动操作 ====================
  AUTO_APPROVE: {
    icon: '⚙',
    iconColor: 'text-blue-400',
    label: 'actions.AUTO_APPROVE',
    labelColor: 'bg-blue-50 text-blue-600',
    showInTimeline: true,
    requiresTargetUser: false,
    requiresComment: false,
    isAdminAction: false,
    isAutoAction: true,
    priority: 60,
  },
  AUTO_REJECT: {
    icon: '⚙',
    iconColor: 'text-red-400',
    label: 'actions.AUTO_REJECT',
    labelColor: 'bg-red-50 text-red-600',
    showInTimeline: true,
    requiresTargetUser: false,
    requiresComment: false,
    isAdminAction: false,
    isAutoAction: true,
    priority: 80,
  },
  
  // ==================== 管理员操作 ⭐ ====================
  ADMIN_APPROVE: {
    icon: '✓',
    iconColor: 'text-green-600',
    label: 'actions.ADMIN_APPROVE',
    labelColor: 'bg-orange-100 text-orange-700 border border-orange-400',
    showInTimeline: true,
    requiresTargetUser: true,
    requiresComment: true,
    isAdminAction: true,
    isAutoAction: false,
    priority: 60,
  },
  ADMIN_REJECT: {
    icon: '✗',
    iconColor: 'text-red-600',
    label: 'actions.ADMIN_REJECT',
    labelColor: 'bg-orange-100 text-orange-700 border border-orange-400',
    showInTimeline: true,
    requiresTargetUser: true,
    requiresComment: true,
    isAdminAction: true,
    isAutoAction: false,
    priority: 80,
  },
  ADMIN_REASSIGN: {
    icon: '⇄',
    iconColor: 'text-orange-600',
    label: 'actions.ADMIN_REASSIGN',
    labelColor: 'bg-orange-100 text-orange-700 border border-orange-400',
    showInTimeline: true,
    requiresTargetUser: true,
    requiresComment: true,
    isAdminAction: true,
    isAutoAction: false,
    priority: 50,
  },
  ADMIN_TERMINATE: {
    icon: '⛔',  // ⭐ 业界标准：红色禁止图标（钉钉/飞书）
    iconColor: 'text-red-600',  // ⭐ 业界标准：红色
    label: 'actions.ADMIN_TERMINATE',
    labelColor: 'bg-red-100 text-red-700 border-2 border-red-600',  // ⭐ 业界标准：红色系
    showInTimeline: true,
    requiresTargetUser: false,
    requiresComment: true,
    isAdminAction: true,
    isAutoAction: false,
    priority: 90,
  },
  
  // ==================== 辅助操作 ====================
  CLAIM: {
    icon: '✋',
    iconColor: 'text-blue-600',
    label: 'actions.CLAIM',
    labelColor: 'bg-blue-100 text-blue-700',
    showInTimeline: false,  // 不在主时间线显示
    requiresTargetUser: false,
    requiresComment: false,
    isAdminAction: false,
    isAutoAction: false,
    priority: 40,
  },
  UNCLAIM: {
    icon: '○',
    iconColor: 'text-gray-600',
    label: 'actions.UNCLAIM',
    labelColor: 'bg-gray-100 text-gray-600',
    showInTimeline: false,  // 不在主时间线显示
    requiresTargetUser: false,
    requiresComment: false,
    isAdminAction: false,
    isAutoAction: false,
    priority: 40,
  },
  REMIND: {
    icon: '🔔',
    iconColor: 'text-yellow-600',
    label: 'actions.REMIND',
    labelColor: 'bg-yellow-100 text-yellow-700',
    showInTimeline: false,  // 不在主时间线显示
    requiresTargetUser: false,
    requiresComment: false,
    isAdminAction: false,
    isAutoAction: false,
    priority: 30,
  },
  EXECUTE: {
    icon: '⚡',  // ⭐ 闪电图标（按文档规范修正）
    iconColor: 'text-blue-600',
    label: 'actions.EXECUTE',
    labelColor: 'bg-blue-100 text-blue-700',
    showInTimeline: true,
    requiresTargetUser: false,
    requiresComment: false,
    isAdminAction: false,
    isAutoAction: true,
    priority: 50,
  },
  COMMENT: {
    icon: '💬',
    iconColor: 'text-gray-600',
    label: 'actions.COMMENT',
    labelColor: 'bg-gray-100 text-gray-600',
    showInTimeline: false,  // 不在主时间线显示
    requiresTargetUser: false,
    requiresComment: false,
    isAdminAction: false,
    isAutoAction: false,
    priority: 30,
  },
};

/**
 * 获取操作类型的元数据
 */
export function getActionMetadata(action: ApprovalAction): ActionDisplayMeta {
  return ACTION_METADATA[action];
}

/**
 * 根据优先级对操作进行排序（降序）
 */
export function sortActionsByPriority(actions: ActionLogItem[]): ActionLogItem[] {
  return [...actions].sort((a, b) => {
    const priorityA = ACTION_METADATA[a.action]?.priority || 0;
    const priorityB = ACTION_METADATA[b.action]?.priority || 0;
    return priorityB - priorityA;  // 降序：优先级高的排前面
  });
}

// ==================== 主要映射函数 ====================

/**
 * 将审批历史和流程定义映射为完整的节点状态字典
 * 
 * 这是主要的入口函数，会：
 * 1. 映射已执行的节点状态（基于 history）
 * 2. 填充未执行的节点状态（基于 processModel）
 * 3. 特殊处理 START 和 END 节点
 * 
 * @param history 后端返回的审批历史数据
 * @param processModel 流程定义模型（包含所有节点）
 * @param instanceStatus 流程实例的整体状态
 * @param submitTime 流程提交时间
 * @param submitter 流程发起人信息
 * @returns 节点ID到状态的完整映射字典
 * 
 * @example
 * ```typescript
 * const nodeStatuses = mapApprovalHistoryToNodeStatuses(
 *   history.items,
 *   processVersion.model,
 *   detail.status,
 *   detail.submitTime,
 *   detail.submitter
 * );
 * // nodeStatuses 包含所有节点（已执行 + 未执行）
 * ```
 */
export function mapApprovalHistoryToNodeStatuses(
  history: HistoryItem[],
  processModel: ProcessModel,
  instanceStatus: InstanceStatus,
  submitTime: string,
  submitter: UserInfo,
  endReason?: string  // ⭐ 新增：流程终止原因（撤回/拒绝/终止时的原因）
): Record<string, NodeStatusMapping> {
  // 1. 先映射已执行的节点
  const nodeStatuses = mapApprovalHistoryToStatuses(history);
  
  // 2. 判断流程是否已终止
  const isFlowTerminated = 
    instanceStatus === 'REJECTED' ||
    instanceStatus === 'TERMINATED' ||
    instanceStatus === 'WITHDRAWN';
  
  // 3. 遍历流程定义中的所有节点，填充或覆盖节点状态
  for (const node of processModel.nodes) {
    // 4. 根据节点类型和流程状态确定节点的状态
    
    // ⭐ START 节点：总是根据提交时间和提交人来设置
    if (node.type === 'START') {
      nodeStatuses[node.id] = createStartNodeStatus(
        submitTime,
        submitter.displayName || submitter.name
      );
      continue; // 跳过后续逻辑
    }
    
    // ⭐ END 节点：总是根据流程的最终状态（instanceStatus）来判断
    // 即使 history 中有 END 节点的记录，也要覆盖它
    if (node.type === 'END') {
      nodeStatuses[node.id] = createEndNodeStatus(instanceStatus, history, endReason);
      continue; // 跳过后续逻辑
    }
    
    // ⭐ 其他节点：需要判断流程是否终止
    const existingStatus = nodeStatuses[node.id];
    
    if (isFlowTerminated) {
      // ⚠️ 流程已终止：识别哪些节点是真正完成的，哪些是应该跳过的
      //
      // 【零技术债原则 - 后端已修复，此处为历史数据兼容】
      // ✅ 新数据（后端已修复）：未执行的节点会正确标记为 SKIPPED
      // ⚠️ 旧数据（历史流程）：可能仍然是 COMPLETED 但没有 operator
      //
      // 判断标准：
      // 1. 状态是 completed/rejected（从 history 中获取）
      // 2. 有实际的操作人（operator 不为空）- 这表示节点真的被执行过
      //
      // 如果 operator 为空，说明：
      // - 这是历史数据（后端修复前的流程实例）
      // - 节点被错误标记为 COMPLETED，但 tasks[].actions 数组为空
      // - 应该在前端兼容处理，显示为 skipped
      //
      // 📅 后端修复时间：2026-01-06
      // 📝 后端修复位置：backend/src/engines/approval/temporal/workflows/generic-approval.workflow.ts
      //
      const isActuallyCompleted = existingStatus && 
        (existingStatus.status === 'completed' || existingStatus.status === 'rejected') &&
        existingStatus.operator && existingStatus.operator.trim() !== '';
      
      if (isActuallyCompleted) {
        // 保留真正已完成或已拒绝的节点
        continue;
      } else {
        // 未完成的节点全部标记为 skipped
        // 包括：
        // - active、pending（未开始）
        // - completed 但没有 operator（历史数据兼容）
        // - skipped（新数据，后端已正确标记）
        
        // ⭐ 【零技术债 - 保留已有操作记录，但不包括ADMIN_TERMINATE】
        // 场景1：有业务操作（如FORWARD、DELEGATE等），保留这些记录
        // 场景2：没有任何业务操作，清空operator让UI显示预设审批人
        // 场景3：管理员强制终止时，ADMIN_TERMINATE操作在END节点显示，不在SKIPPED显示
        if (existingStatus && (existingStatus.operator || existingStatus.completedActions?.length)) {
          // 有操作记录：保留（如王经理转交给李经理）
          nodeStatuses[node.id] = {
            ...existingStatus,
            status: 'skipped',
            comment: existingStatus.comment || '流程已终止，但已有部分操作记录',
            // ⭐ 零技术债重构 - 2026-01-08：过滤掉ADMIN_TERMINATE
            completedActions: existingStatus.completedActions?.filter(act => act.action !== ActionType.ADMIN_TERMINATE),
          };
        } else {
          // 没有操作记录：清空operator，UI会显示预设审批人
          nodeStatuses[node.id] = {
            status: 'skipped',
            completedAt: '',
            operator: '',
            comment: '流程已终止，此节点未执行',
          };
        }
      }
    } else {
      // 流程未终止：如果节点不在 history 中，标记为 pending
      if (!existingStatus) {
        nodeStatuses[node.id] = {
          status: 'pending',
          completedAt: '',
          operator: '',
          comment: '',
        };
      }
      // 如果已在 history 中，保留原状态
    }
  }
  
  return nodeStatuses;
}

/**
 * 将审批历史数据映射为节点状态字典（仅已执行节点）
 * 
 * @param history 后端返回的审批历史数据
 * @returns 节点ID到状态的映射字典
 * 
 * @example
 * ```typescript
 * const history = await getApprovalHistory(instanceId);
 * const nodeStatuses = mapApprovalHistoryToStatuses(history.items);
 * // nodeStatuses = { 'node_1': { status: 'rejected', comment: '不符合要求', ... } }
 * ```
 */
export function mapApprovalHistoryToStatuses(
  history: HistoryItem[]
): Record<string, NodeStatusMapping> {
  const nodeStatuses: Record<string, NodeStatusMapping> = {};
  
  for (const historyNode of history) {
    const mapping = mapSingleNodeStatus(historyNode);
    nodeStatuses[historyNode.nodeId] = mapping;
  }
  
  return nodeStatuses;
}

/**
 * 映射单个节点的状态
 * 
 * @param historyNode 历史节点数据
 * @returns 节点状态映射结果
 */
function mapSingleNodeStatus(historyNode: HistoryItem): NodeStatusMapping {
  // 1. 初始化结果
  let status: NodeDisplayStatus = 'pending';
  let operator = '';
  let comment = '';
  let completedAt = historyNode.endTime || '';  // ⭐ 改为 let，允许 ACTIVE 状态下重新赋值
  let isAdminAction = false;
  let targetUser: string | undefined;
  let autoApproveReason: string | undefined;
  let errorDetails: string | undefined;
  let action: ApprovalAction | undefined;
  
  // 2. 收集所有操作动作
  const allActions = collectAllActions(historyNode);
  
  // ⭐⭐ 新增：处理多操作场景（零技术债方案 - 2026-01-07）
  // 按时间排序所有操作，用于时间线显示
  const sortedActions = sortActionsByTime(allActions);
  
  // ⭐ 调试日志（2026-01-08）
  if (historyNode.status === 'ACTIVE' && allActions.length > 0) {
    console.log(`[status-mapper] ACTIVE节点"${historyNode.nodeName}" 收集到 ${allActions.length} 个操作:`, 
      allActions.map(a => `${a.operator?.name} ${a.action}`)
    );
  }
  
  // 确定最终操作（用于节点状态判断）
  const finalAction = determineFinalActionByPriority(sortedActions);
  
  // 3. 根据节点状态和操作类型综合判断
  switch (historyNode.status) {
    case 'COMPLETED':
      // 节点已完成，需要根据操作类型判断业务结果
      const result = determineCompletedNodeResult(allActions, historyNode);
      status = result.status;
      operator = result.operator;
      comment = result.comment;
      action = result.action;  // ⭐ 记录操作类型
      isAdminAction = result.isAdminAction || false;
      targetUser = result.targetUser;
      autoApproveReason = result.autoApproveReason;
      errorDetails = result.errorDetails;
      break;
      
    case 'ACTIVE':
    case 'ASSIGNED':
      status = 'active';
      
      // ⭐ 会签场景：获取所有当前待审批的人（支持多个task）
      const currentTasks = historyNode.tasks || [];
      
      // 单人审批：取第一个task的审批人
      const currentTask = currentTasks[0];
      const currentAssignee = currentTask && currentTask.assignee 
        ? (currentTask.assignee.displayName || currentTask.assignee.name)
        : '';
      
      // ⭐ 会签场景：提取所有审批人（2026-01-08优化：区分待审批和已审批）
      const allCurrentAssignees = currentTasks
        .map(t => t.assignee?.displayName || t.assignee?.name)
        .filter(Boolean);
      
      // ⭐ 会签场景：只提取待审批的人（状态为ASSIGNED的task）
      const pendingAssignees = currentTasks
        .filter(t => t.status === 'ASSIGNED' || t.status === 'PENDING' || t.status === 'CREATED')
        .map(t => t.assignee?.displayName || t.assignee?.name)
        .filter(Boolean);
      
      // 检查是否有流程控制操作（转交、加签等）
      if (allActions.length > 0) {
        const lastAction = allActions[allActions.length - 1];
        comment = lastAction.comment || '';
        completedAt = lastAction.actionTime || '';  // ⭐ ACTIVE状态也需要显示操作时间
        
        // ⭐ 对于转交/委托/加签操作，operator 显示完整的操作信息
        if (lastAction.action === ActionType.FORWARD) {
          const fromUser = lastAction.operator.displayName || lastAction.operator.name;
          const toUser = lastAction.targetUser?.displayName || lastAction.targetUser?.name || currentAssignee;
          operator = `${fromUser} 转交给 ${toUser}`;  // ⭐ 按文档规范
          targetUser = toUser;
          action = ActionType.FORWARD;  // ⭐ 记录操作类型
        } else if (lastAction.action === ActionType.DELEGATE) {
          const fromUser = lastAction.operator.displayName || lastAction.operator.name;
          const toUser = lastAction.targetUser?.displayName || lastAction.targetUser?.name || currentAssignee;
          operator = `${fromUser} 委托给 ${toUser}`;  // ⭐ 按文档规范
          targetUser = toUser;
          action = ActionType.DELEGATE;  // ⭐ 记录操作类型
        } else if (lastAction.action === ActionType.ADD_SIGN) {
          const fromUser = lastAction.operator.displayName || lastAction.operator.name;
          const toUser = lastAction.targetUser?.displayName || lastAction.targetUser?.name || currentAssignee;
          operator = `${fromUser} 加签给 ${toUser}`;  // ⭐ 按文档规范（零技术债 - 2026-01-07）
          targetUser = toUser;
          action = ActionType.ADD_SIGN;  // ⭐ 记录操作类型
        } else if (lastAction.action === ActionType.ADMIN_REASSIGN) {
          const adminName = lastAction.operator.displayName || lastAction.operator.name;
          const newAssignee = lastAction.targetUser?.displayName || lastAction.targetUser?.name || currentAssignee;
          operator = `管理员 ${adminName} 重新分配给 ${newAssignee}`;  // ⭐ 按文档规范
          targetUser = newAssignee;
          isAdminAction = true;
          action = ActionType.ADMIN_REASSIGN;  // ⭐ 记录操作类型
        } else if (lastAction.targetUser) {
          // 其他需要 targetUser 的操作
          operator = lastAction.operator.displayName || lastAction.operator.name;
          targetUser = lastAction.targetUser.displayName || lastAction.targetUser.name;
          action = lastAction.action;  // ⭐ 记录操作类型
        } else {
          // ⭐⭐ 零技术债重构 - 2026-01-08
          // 没有 targetUser 的操作（如APPROVE/REJECT）
          // operator 显示最后一个操作人，待审批人由 pendingApprovals 字段显示
          operator = lastAction.operator.displayName || lastAction.operator.name;
          action = lastAction.action;  // ⭐ 记录操作类型
        }
      } else {
        // ⭐⭐ 零技术债重构 - 2026-01-08
        // 没有操作记录：operator 显示第一个待审批人（或第一个审批人）
        // 会签场景的所有待审批人由 pendingApprovals 字段显示
        if (pendingAssignees.length > 0) {
          operator = pendingAssignees[0];  // 第一个待审批人
        } else if (allCurrentAssignees.length > 0) {
          operator = allCurrentAssignees[0];  // 兜底：第一个审批人
        } else {
          operator = currentAssignee;  // 完全没有信息
        }
      }
      break;
      
    case 'CANCELLED':
      status = 'cancelled';
      // ⭐ CANCELLED 状态：流程被撤回/终止，但需要显示已执行的操作（如转交）
      // 使用最终操作来确定显示内容
      if (finalAction) {
        comment = finalAction.comment || '';
        action = finalAction.action;
        
        // ⭐ 根据操作类型格式化 operator 字符串
        if (finalAction.action === ActionType.FORWARD) {
          const fromUser = finalAction.operator.displayName || finalAction.operator.name;
          const toUser = finalAction.targetUser?.displayName || finalAction.targetUser?.name || '';
          operator = `${fromUser} 转交给 ${toUser}`;
          targetUser = toUser;
        } else if (finalAction.action === ActionType.DELEGATE) {
          const fromUser = finalAction.operator.displayName || finalAction.operator.name;
          const toUser = finalAction.targetUser?.displayName || finalAction.targetUser?.name || '';
          operator = `${fromUser} 委托给 ${toUser}`;
          targetUser = toUser;
        } else if (finalAction.action === ActionType.ADD_SIGN) {
          const fromUser = finalAction.operator.displayName || finalAction.operator.name;
          const toUser = finalAction.targetUser?.displayName || finalAction.targetUser?.name || '';
          operator = `${fromUser} 加签给 ${toUser}`;  // ⭐ 零技术债 - 2026-01-07
          targetUser = toUser;
        } else if (finalAction.action === ActionType.ADMIN_REASSIGN) {
          const adminName = finalAction.operator.displayName || finalAction.operator.name;
          const newAssignee = finalAction.targetUser?.displayName || finalAction.targetUser?.name || '';
          operator = `管理员 ${adminName} 重新分配给 ${newAssignee}`;
          targetUser = newAssignee;
          isAdminAction = true;
        } else {
          // 其他操作类型：直接使用操作人名称
          operator = finalAction.operator.displayName || finalAction.operator.name;
          
          if (finalAction.action.startsWith('ADMIN_')) {
            isAdminAction = true;
          }
          
          if (finalAction.targetUser) {
            targetUser = finalAction.targetUser.displayName || finalAction.targetUser.name;
          }
        }
      }
      break;
      
    case 'FAILED':
      status = 'failed';
      // FAILED 节点的错误信息从 comment 或特定字段获取
      if (allActions.length > 0) {
        const failedAction = allActions[0];
        operator = '系统处理失败';
        comment = failedAction?.comment || '未知错误';
        // ⭐ 提取错误详情
        errorDetails = (failedAction as any)?.errorDetails || (failedAction as any)?.stackTrace;
      }
      break;
      
    case 'SKIPPED':
      status = 'skipped';
      // ⭐ SKIPPED 状态：节点被跳过，但可能有部分操作（如转交、委托等）
      // 
      // 【重要】SKIPPED节点不显示ADMIN_TERMINATE操作（它在END节点显示）
      // 只显示业务操作：FORWARD、DELEGATE、ADMIN_REASSIGN等
      // 
      // 场景1：王经理转交给李经理，然后管理员终止
      //   - actions: [FORWARD, ADMIN_TERMINATE]
      //   - 应该显示：王经理 转交给 李经理（FORWARD）
      //   - 不显示：IT Administrator（ADMIN_TERMINATE）
      // 
      // 场景2：没有任何业务操作，管理员直接终止
      //   - actions: [ADMIN_TERMINATE]
      //   - 不显示操作记录，UI层显示预设审批人
      
      // 从sortedActions中排除ADMIN_TERMINATE，找第一个业务操作
      const businessAction = sortedActions.find(a => a.action !== ActionType.ADMIN_TERMINATE);
      
      if (businessAction) {
        // 有业务操作：使用该操作
        comment = businessAction.comment || '';
        action = businessAction.action;
        
        // ⭐ 根据操作类型格式化 operator 字符串
        if (businessAction.action === ActionType.FORWARD) {
          const fromUser = businessAction.operator.displayName || businessAction.operator.name;
          const toUser = businessAction.targetUser?.displayName || businessAction.targetUser?.name || '';
          operator = `${fromUser} 转交给 ${toUser}`;
          targetUser = toUser;
        } else if (businessAction.action === ActionType.DELEGATE) {
          const fromUser = businessAction.operator.displayName || businessAction.operator.name;
          const toUser = businessAction.targetUser?.displayName || businessAction.targetUser?.name || '';
          operator = `${fromUser} 委托给 ${toUser}`;
          targetUser = toUser;
        } else if (businessAction.action === ActionType.ADMIN_REASSIGN) {
          const adminName = businessAction.operator.displayName || businessAction.operator.name;
          const newAssignee = businessAction.targetUser?.displayName || businessAction.targetUser?.name || '';
          operator = `管理员 ${adminName} 重新分配给 ${newAssignee}`;
          targetUser = newAssignee;
          isAdminAction = true;
        } else {
          // 其他操作类型：直接使用操作人名称
          operator = businessAction.operator.displayName || businessAction.operator.name;
          
          if (businessAction.action.startsWith('ADMIN_')) {
            isAdminAction = true;
          }
          
          if (businessAction.targetUser) {
            targetUser = businessAction.targetUser.displayName || businessAction.targetUser.name;
          }
        }
      }
      // 如果没有业务操作（只有ADMIN_TERMINATE），operator保持空，UI会显示预设审批人
      break;
      
    case 'PENDING':
    default:
      status = 'pending';
      break;
  }
  
  // ⭐⭐ 【零技术债 - SKIPPED节点排除ADMIN_TERMINATE】
  // SKIPPED节点不显示ADMIN_TERMINATE操作（它在END节点显示）
  // 只返回业务操作：FORWARD、DELEGATE等
  let actionsToReturn = sortedActions;
  if (status === 'skipped') {
    actionsToReturn = sortedActions.filter(act => act.action !== ActionType.ADMIN_TERMINATE);
  }
  
  // ⭐⭐ 【零技术债修复 - 2026-01-07】增强allActions的targetUser
  // 对于ADMIN_APPROVE/ADMIN_REJECT，如果后端没有提供targetUser，从task.assignee推断
  const enhancedActions = actionsToReturn.map(act => {
    let enhancedTargetUser = act.targetUser;
    
    // 如果是管理员代审批操作且没有targetUser，从task.assignee推断
    if ((act.action === ActionType.ADMIN_APPROVE || act.action === ActionType.ADMIN_REJECT) && !enhancedTargetUser) {
      if (historyNode.tasks && historyNode.tasks[0]) {
        const task = historyNode.tasks[0];
        enhancedTargetUser = task.assignee;
      }
    }
    
    return {
      id: (act as any).id || '',
      action: act.action,
      operator: act.operator,
      targetUser: enhancedTargetUser,
      comment: act.comment,
      actionTime: act.actionTime,
    };
  });
  
  return {
    status,
    completedAt,
    operator,
    comment,
    action,  // ⭐ 记录操作类型
    isAdminAction,
    targetUser,
    autoApproveReason,
    errorDetails,
    
    // ⭐⭐ 已完成的操作记录（零技术债重构 - 2026-01-08，重命名自 allActions）
    // SKIPPED状态：只要有业务操作就返回（即使只有1个），排除ADMIN_TERMINATE
    // ACTIVE状态：只要有操作就返回（即使只有1个）- 会签场景
    // 其他状态：只有多个操作时才返回
    completedActions: (() => {
      const shouldReturn = (status === 'skipped' && enhancedActions.length > 0) 
                        || (status === 'active' && enhancedActions.length > 0)
                        || enhancedActions.length > 1;
      
      return shouldReturn ? enhancedActions : undefined;
    })(),
    
    // ⭐⭐⭐ 待审批的任务（零技术债重构 - 2026-01-08 新增）
    // 仅在 ACTIVE 状态且有多个待审批人时填充（会签场景）
    pendingApprovals: (() => {
      if (status !== 'active' || !historyNode.tasks) {
        return undefined;
      }
      
      // 提取所有待审批的任务（状态为ASSIGNED/PENDING/CREATED）
      const pendingTasks = historyNode.tasks.filter(
        t => t.status === 'ASSIGNED' || t.status === 'PENDING' || t.status === 'CREATED'
      );
      
      // 如果没有待审批任务，或只有一个且没有已完成操作，不返回此字段
      // （单人审批场景用 operator 字段即可）
      if (pendingTasks.length === 0) {
        return undefined;
      }
      
      // 会签场景：多个待审批人，或有已完成操作
      if (pendingTasks.length > 1 || enhancedActions.length > 0) {
        return pendingTasks
          .map(task => ({
            taskId: task.id || '',
            assignee: task.assignee || { id: '', name: '未知', displayName: '未知' },
            assignedAt: task.createdAt || task.assignedAt || '',
          }))
          .filter(p => p.assignee.name !== '未知');
      }
      
      return undefined;
    })(),
  };
}

/**
 * 收集节点下所有任务的所有操作
 * 
 * @param historyNode 历史节点数据
 * @returns 所有操作的数组
 */
function collectAllActions(historyNode: HistoryItem): ActionLogItem[] {
  const allActions: ActionLogItem[] = [];
  
  for (const task of historyNode.tasks) {
    if (task.actions && task.actions.length > 0) {
      allActions.push(...task.actions);
    }
  }
  
  return allActions;
}

// ⭐⭐ 新增：多操作支持辅助函数（零技术债方案 - 2026-01-07）

/**
 * 按时间排序操作（升序）
 * 用于时间线显示，按操作发生的时间先后顺序排列
 * 
 * @param actions 操作列表
 * @returns 按时间排序的操作列表
 */
function sortActionsByTime(actions: ActionLogItem[]): ActionLogItem[] {
  return [...actions].sort((a, b) => {
    const timeA = new Date(a.actionTime).getTime();
    const timeB = new Date(b.actionTime).getTime();
    return timeA - timeB;  // 升序：早的排前面
  });
}

/**
 * 根据优先级确定最终操作
 * 用于确定节点的最终状态（图标、标签）
 * 
 * 优先级规则（数字越大优先级越高）：
 * - 100: 系统异常（FAILED）
 * - 90: 管理员强制终止（ADMIN_TERMINATE）
 * - 80: 拒绝类（REJECT, ADMIN_REJECT, AUTO_REJECT）
 * - 70: 退回（RETURN）
 * - 60: 通过类（APPROVE, ADMIN_APPROVE, AUTO_APPROVE）
 * - 50: 流程控制（FORWARD, ADD_SIGN, DELEGATE, ADMIN_REASSIGN）
 * 
 * @param actions 操作列表（已按时间排序）
 * @returns 优先级最高的操作
 * 
 * @example
 * // 场景：会签中一人拒绝
 * const actions = [
 *   { action: 'APPROVE', ... },  // 王经理通过
 *   { action: 'APPROVE', ... },  // 李副经理通过
 *   { action: 'REJECT', ... },   // 张主管拒绝（优先级最高）
 * ];
 * const final = determineFinalActionByPriority(actions);
 * // final.action === 'REJECT'，节点最终状态为"已拒绝"
 */
function determineFinalActionByPriority(actions: ActionLogItem[]): ActionLogItem | null {
  if (actions.length === 0) {
    return null;
  }
  
  if (actions.length === 1) {
    return actions[0];
  }
  
  // 找到优先级最高的操作
  return actions.reduce((highest, current) => {
    const currentPriority = ACTION_METADATA[current.action]?.priority || 0;
    const highestPriority = ACTION_METADATA[highest.action]?.priority || 0;
    return currentPriority > highestPriority ? current : highest;
  });
}

/**
 * 判断已完成节点的业务结果
 * 
 * 优先级（从高到低）：
 * 1. 系统失败（FAILED） - 最高优先级
 * 2. 管理员强制终止（ADMIN_TERMINATE）
 * 3. 拒绝类操作（REJECT, AUTO_REJECT, ADMIN_REJECT）
 * 4. 退回操作（RETURN）
 * 5. 通过类操作（APPROVE, SUBMIT, AUTO_APPROVE, ADMIN_APPROVE）
 * 6. 流程控制操作（FORWARD, ADD_SIGN, DELEGATE, etc.）
 * 
 * @param actions 节点的所有操作
 * @param historyNode 历史节点数据（用于获取task.assignee等信息）
 * @returns 业务结果（含管理员操作和目标用户信息）
 */
function determineCompletedNodeResult(actions: ActionLogItem[], historyNode: HistoryItem): {
  status: NodeDisplayStatus;
  operator: string;
  comment: string;
  isAdminAction?: boolean;
  targetUser?: string;
  autoApproveReason?: string;
  errorDetails?: string;
  action?: ApprovalAction;  // ⭐ 添加原始操作类型
} {
  // 0. 系统失败优先级最高（理论上不应该在 COMPLETED 节点出现，但需要处理）
  // FAILED 状态应该由 NodeStatus 直接判断，这里主要处理其他操作
  
  // 1. 管理员强制终止（次高优先级）
  const adminTerminateAction = actions.find(a => a.action === ActionType.ADMIN_TERMINATE);
  if (adminTerminateAction) {
    const operatorName = adminTerminateAction.operator.displayName || adminTerminateAction.operator.name;
    return {
      status: 'terminated',
      operator: `管理员 ${operatorName} 强制终止流程`,  // ⭐ 按文档规范添加后缀
      comment: adminTerminateAction.comment || '',
      isAdminAction: true,
      action: ActionType.ADMIN_TERMINATE,  // ⭐ 记录操作类型
    };
  }
  
  // 2. 拒绝类操作（含管理员代审批拒绝）
  const rejectAction = actions.find(a => 
    a.action === ActionType.REJECT || 
    a.action === ActionType.AUTO_REJECT ||
    a.action === ActionType.ADMIN_REJECT
  );
  if (rejectAction) {
    if (rejectAction.action === ActionType.ADMIN_REJECT) {
      // 管理员代审批拒绝
      const operatorName = rejectAction.operator.displayName || rejectAction.operator.name;
      
      // ⭐ 零技术债修复（2026-01-07）：如果后端没有提供targetUser，从task.assignee推断
      let targetName = rejectAction.targetUser?.displayName || rejectAction.targetUser?.name;
      if (!targetName && historyNode.tasks && historyNode.tasks[0]) {
        const task = historyNode.tasks[0];
        targetName = task.assignee?.displayName || task.assignee?.name;
      }
      if (!targetName) {
        targetName = '原审批人';  // 最终兜底
      }
      
      return {
        status: 'rejected',
        operator: `管理员 ${operatorName} 代 ${targetName} 审批拒绝`,  // ⭐ 按文档规范添加"拒绝"后缀
        comment: rejectAction.comment || '',
        isAdminAction: true,
        targetUser: targetName,
        action: ActionType.ADMIN_REJECT,  // ⭐ 记录操作类型
      };
    } else if (rejectAction.action === ActionType.AUTO_REJECT) {
      // 自动拒绝
      return {
        status: 'rejected',
        operator: '系统自动拒绝',
        comment: rejectAction.comment || '',
        autoApproveReason: rejectAction.comment,
        action: ActionType.AUTO_REJECT,  // ⭐ 记录操作类型
      };
    } else {
      // 普通拒绝
      const operatorName = rejectAction.operator.displayName || rejectAction.operator.name;
      return {
        status: 'rejected',
        operator: `${operatorName} 审批拒绝`,  // ⭐ 按文档规范添加操作标签
        comment: rejectAction.comment || '',
        action: ActionType.REJECT,  // ⭐ 记录操作类型
      };
    }
  }
  
  // 3. 退回操作
  const returnAction = actions.find(a => a.action === ActionType.RETURN);
  if (returnAction) {
    const operatorName = returnAction.operator.displayName || returnAction.operator.name;
    // ⭐ TODO: targetNodeName 需要从后端返回，暂时显示"退回"
    return {
      status: 'returned',
      operator: `${operatorName} 退回`,  // ⭐ 按文档规范添加操作标签（完整格式需要目标节点信息）
      comment: returnAction.comment || '',
      action: ActionType.RETURN,  // ⭐ 记录操作类型
    };
  }
  
  // 4. 通过类操作（含管理员代审批通过和自动通过）
  const approveActions = actions.filter(a => 
    a.action === ActionType.APPROVE || 
    a.action === ActionType.SUBMIT || 
    a.action === ActionType.AUTO_APPROVE ||
    a.action === ActionType.ADMIN_APPROVE
  );
  
  if (approveActions.length > 0) {
    // ⭐ 特殊处理：SUBMIT（提交申请）
    const submitAction = approveActions.find(a => a.action === ActionType.SUBMIT);
    if (submitAction && approveActions.length === 1) {
      // 如果只有 SUBMIT，显示"提交申请"
      const operatorName = submitAction.operator.displayName || submitAction.operator.name;
      return {
        status: 'completed',
        operator: `${operatorName} 提交申请`,  // ⭐ 按文档规范
        comment: submitAction.comment || '',
        action: ActionType.SUBMIT,  // ⭐ 记录操作类型
      };
    }
    
    // 检查是否有管理员操作
    const adminApproveAction = approveActions.find(a => a.action === ActionType.ADMIN_APPROVE);
    if (adminApproveAction) {
      const operatorName = adminApproveAction.operator.displayName || adminApproveAction.operator.name;
      
      // ⭐ 零技术债修复（2026-01-07）：如果后端没有提供targetUser，从task.assignee推断
      let targetName = adminApproveAction.targetUser?.displayName || adminApproveAction.targetUser?.name;
      if (!targetName && historyNode.tasks && historyNode.tasks[0]) {
        const task = historyNode.tasks[0];
        targetName = task.assignee?.displayName || task.assignee?.name;
      }
      if (!targetName) {
        targetName = '原审批人';  // 最终兜底
      }
      
      return {
        status: 'completed',
        operator: `管理员 ${operatorName} 代 ${targetName} 审批通过`,  // ⭐ 按文档规范添加"通过"后缀
        comment: adminApproveAction.comment || '',
        isAdminAction: true,
        targetUser: targetName,
        action: ActionType.ADMIN_APPROVE,  // ⭐ 记录操作类型
      };
    }
    
    // 检查是否有自动通过
    const autoApproveAction = approveActions.find(a => a.action === ActionType.AUTO_APPROVE);
    if (autoApproveAction) {
      return {
        status: 'completed',
        operator: '系统自动通过',
        comment: autoApproveAction.comment || '',
        autoApproveReason: autoApproveAction.comment,
        action: ActionType.AUTO_APPROVE,  // ⭐ 记录操作类型
      };
    }
    
    // 普通通过（可能是多人会签）
    const operators = approveActions.map(a => 
      a.operator.displayName || a.operator.name
    );
    
    // 取最后一个有 comment 的操作的评论
    const lastCommentAction = [...approveActions].reverse().find(a => a.comment);
    
    return {
      status: 'completed',
      operator: `${operators.join('、')} 审批通过`,  // ⭐ 按文档规范添加操作标签
      comment: lastCommentAction?.comment || '',
      action: ActionType.APPROVE,  // ⭐ 记录操作类型
    };
  }
  
  // 5. 流程控制操作（转交、加签、委托、重新分配等）
  // 这些操作通常不会导致节点完成，但需要记录
  const processControlActions = actions.filter(a =>
    a.action === ActionType.FORWARD ||
    a.action === ActionType.ADD_SIGN ||
    a.action === ActionType.DELEGATE ||
    a.action === ActionType.ADMIN_REASSIGN
  );
  
  if (processControlActions.length > 0) {
    const lastAction = processControlActions[processControlActions.length - 1];
    const operatorName = lastAction.operator.displayName || lastAction.operator.name;
    const targetName = lastAction.targetUser?.displayName || lastAction.targetUser?.name;
    
    let actionLabel = '';
    let isAdmin = false;
    
    switch (lastAction.action) {
      case ActionType.FORWARD:
        actionLabel = '转交给';
        break;
      case ActionType.ADD_SIGN:
        actionLabel = '加签';
        break;
      case ActionType.DELEGATE:
        actionLabel = '委托给';
        break;
      case ActionType.ADMIN_REASSIGN:
        actionLabel = '重新分配给';
        isAdmin = true;
        break;
    }
    
    const operator = isAdmin 
      ? `管理员 ${operatorName} ${actionLabel} ${targetName || ''}`
      : `${operatorName} ${actionLabel} ${targetName || ''}`;
    
    return {
      status: 'active',  // 这些操作后节点仍然是活动状态
      operator: operator.trim(),
      comment: lastAction.comment || '',
      isAdminAction: isAdmin,
      targetUser: targetName,
      action: lastAction.action,  // ⭐ 记录操作类型
    };
  }
  
  // 6. 自动操作（升级、执行服务任务）
  const escalateAction = actions.find(a => a.action === ActionType.ESCALATE);
  if (escalateAction) {
    const targetName = escalateAction.targetUser?.displayName || escalateAction.targetUser?.name || '上级';
    return {
      status: 'active',  // ⭐ 升级后节点仍然活动，等待新审批人处理
      operator: `系统自动升级至 ${targetName}`,  // ⭐ 按文档规范
      comment: escalateAction.comment || '',
      autoApproveReason: escalateAction.comment,
      targetUser: targetName,
      action: ActionType.ESCALATE,  // ⭐ 记录操作类型
    };
  }
  
  const executeAction = actions.find(a => a.action === ActionType.EXECUTE);
  if (executeAction) {
    return {
      status: 'completed',
      operator: '系统执行服务任务',  // ⭐ 按文档规范
      comment: executeAction.comment || '',
      autoApproveReason: executeAction.comment,
      action: ActionType.EXECUTE,  // ⭐ 记录操作类型
    };
  }
  
  // 7. 审批人撤销操作
  const approverWithdrawAction = actions.find(a => a.action === ActionType.APPROVER_WITHDRAW);
  if (approverWithdrawAction) {
    const operatorName = approverWithdrawAction.operator.displayName || approverWithdrawAction.operator.name;
    return {
      status: 'returned',  // ⭐ 撤销后节点需要重新审批
      operator: `${operatorName} 撤销审批`,  // ⭐ 按文档规范
      comment: approverWithdrawAction.comment || '',
      action: ActionType.APPROVER_WITHDRAW,  // ⭐ 记录操作类型
    };
  }
  
  // 8. 兜底：没有明确操作的完成节点（理论上不应该出现）
  return {
    status: 'completed',
    operator: '',
    comment: '',
  };
}

/**
 * 创建 START 节点的状态（用于流程发起人）
 * 
 * @param submitTime 提交时间
 * @param submitterName 提交人姓名
 * @returns START 节点状态映射
 */
export function createStartNodeStatus(
  submitTime: string,
  submitterName: string
): NodeStatusMapping {
  return {
    status: 'completed',
    completedAt: submitTime,
    operator: `${submitterName} 提交申请`,  // ⭐ 按文档规范添加操作标签
    comment: '',
    action: 'SUBMIT',  // ⭐ 标记为SUBMIT操作
  };
}

/**
 * 创建 END 节点的状态
 * 
 * END 节点的状态取决于整个流程的结果：
 * - APPROVED: 已通过（completed）
 * - REJECTED: 已拒绝（rejected）
 * - TERMINATED: 已终止（skipped）
 * - WITHDRAWN: 已撤回（cancelled）
 * - 其他: 待执行（pending）
 * 
 * @param instanceStatus 流程实例状态
 * @param history 审批历史（用于获取最后的完成时间）
 * @returns END 节点状态映射
 */
export function createEndNodeStatus(
  instanceStatus: InstanceStatus,
  history: HistoryItem[],
  endReason?: string  // ⭐ 流程终止原因（撤回/拒绝/终止时的原因）
): NodeStatusMapping {
  const lastHistoryItem = history[history.length - 1];
  const completedAt = lastHistoryItem?.endTime || '';
  
  // 检查是否有管理员强制终止操作
  let isAdminTerminate = false;
  let adminOperator = '';
  
  // ⭐ 检查是否有撤回操作
  let withdrawOperator = '';
  
  for (const historyNode of history) {
    const allActions = collectAllActions(historyNode);
    
    // 查找管理员强制终止
    const terminateAction = allActions.find(a => a.action === ActionType.ADMIN_TERMINATE);
    if (terminateAction) {
      isAdminTerminate = true;
      adminOperator = terminateAction.operator.displayName || terminateAction.operator.name;
      break;
    }
    
    // ⭐ 查找撤回操作（按文档规范添加）
    const withdrawAction = allActions.find(a => a.action === ActionType.WITHDRAW);
    if (withdrawAction) {
      withdrawOperator = withdrawAction.operator.displayName || withdrawAction.operator.name;
    }
  }
  
  switch (instanceStatus) {
    case 'APPROVED':
      // ⭐ 方案A：流程通过时不显示详情（已在中间节点显示）
      return {
        status: 'completed',
        completedAt,
        operator: '',
        comment: '',
      };
      
    case 'REJECTED':
      // ⭐ 方案A：流程拒绝时不显示详情（拒绝信息已在中间审批节点显示）
      // 拒绝人、拒绝原因等信息已经在拒绝操作的审批节点中完整展示
      // END节点不重复显示，避免信息冗余
      return {
        status: 'rejected',
        completedAt,
        operator: '',
        comment: '',
      };
      
    case 'TERMINATED':
      // 管理员强制终止
      return {
        status: 'terminated',
        completedAt,
        operator: adminOperator ? `管理员 ${adminOperator} 强制终止流程` : '',  // ⭐ 按文档规范添加后缀
        comment: endReason || '流程已终止',
        isAdminAction: isAdminTerminate,
      };
      
    case 'WITHDRAWN':
      // ⭐ 撤回操作：显示"XXX 撤回申请"（按文档规范）
      // 注意：只有用户填写了撤回原因时才显示，否则为空（符合业界习惯）
      return {
        status: 'cancelled',
        completedAt,
        operator: withdrawOperator ? `${withdrawOperator} 撤回申请` : '',
        comment: endReason || undefined,  // ⭐ 无原因时不显示默认文案
      };
      
    default:
      return {
        status: 'pending',
        completedAt: '',
        operator: '',
        comment: '',
      };
  }
}

/**
 * 检查节点是否被拒绝
 * 
 * @param nodeStatus 节点状态映射
 * @returns 是否被拒绝
 */
export function isNodeRejected(nodeStatus: NodeStatusMapping): boolean {
  return nodeStatus.status === 'rejected';
}

/**
 * 检查节点是否已完成（通过或拒绝）
 * 
 * @param nodeStatus 节点状态映射
 * @returns 是否已完成
 */
export function isNodeFinished(nodeStatus: NodeStatusMapping): boolean {
  return nodeStatus.status === 'completed' || 
         nodeStatus.status === 'rejected' ||
         nodeStatus.status === 'returned';
}

/**
 * 获取节点状态的友好描述（用于调试）
 * 
 * @param nodeStatus 节点状态映射
 * @returns 状态描述字符串
 */
export function getNodeStatusDescription(nodeStatus: NodeStatusMapping): string {
  const statusTexts: Record<NodeDisplayStatus, string> = {
    pending: '待执行',
    active: '执行中',
    completed: '已通过',
    rejected: '已拒绝',
    returned: '已退回',
    cancelled: '已取消',
    terminated: '已终止',
    failed: '失败',
    skipped: '跳过',
  };
  
  const statusText = statusTexts[nodeStatus.status] || nodeStatus.status;
  const operatorText = nodeStatus.operator ? ` (${nodeStatus.operator})` : '';
  const commentText = nodeStatus.comment ? ` - ${nodeStatus.comment}` : '';
  
  return `${statusText}${operatorText}${commentText}`;
}

