import { FlowLabEngine, BaseNode, INodeContext, StepType } from '../main/src'; // 假设库代码在此

// ---------- 定义各个操作对应的节点 ----------

// 节点 1: 获取用户信息 (继承 BaseNode 以便封装重试逻辑，虽然也可以在步骤配置里加)
class FetchUserNode extends BaseNode {
  readonly metadata = { id: 'fetch-user', description: '获取用户信息' };
  async execute(context: INodeContext): Promise<void> {
    const userId = context.input.userId;
    context.log(`获取用户 ${userId} ...`);
    // 实际应调用 fetchUserService，这里直接模拟
    await new Promise(res => setTimeout(res, 50));
    if (Math.random() < 0.1 && context.retries === 0) { // 模拟第一次可能失败
       throw new Error('用户服务暂时不可用 (模拟)');
    }
    context.output = { userId, email: `${userId}@test.com`, vipLevel: Math.random() > 0.5 ? 'VIP' : 'Normal' };
  }
}

// 节点 2: 获取商品信息 (简单函数节点)
async function fetchProductNodeFunc(context: INodeContext) {
  const productId = context.input.productId;
  context.log(`获取商品 ${productId} ...`);
  // 实际应调用 fetchProductService
  await new Promise(res => setTimeout(res, 60));
  if (Math.random() < 0.1 && context.retries === 0) { // 模拟第一次可能失败
    throw new Error('商品服务暂时不可用 (模拟)');
  }
  const stock = Math.floor(Math.random() * 5);
  context.output = { productId, price: 100, stock };
}

// 节点 3: 计算价格 (简单函数节点)
async function calculatePriceNodeFunc(context: INodeContext) {
  const price = context.input.price;
  const vipLevel = context.input.vipLevel;
  let finalPrice = price;
  if (vipLevel === 'VIP') {
    finalPrice = price * 0.9;
    context.log(`VIP 用户，应用折扣。最终价格: ${finalPrice}`);
  } else {
    context.log(`普通用户。最终价格: ${finalPrice}`);
  }
  context.output = { finalPrice }; // 设置输出
}

// 节点 4: 创建订单 (简单函数节点)
async function createOrderNodeFunc(context: INodeContext) {
  const { userId, productId, price } = context.input;
  context.log(`创建订单: 用户 ${userId}, 商品 ${productId}, 价格 ${price}`);
  // 实际应调用 createOrderService
  await new Promise(res => setTimeout(res, 70));
   if (Math.random() < 0.05) {
       throw new Error('订单服务创建失败 (模拟)');
   }
  context.output = { orderId: `order-${Date.now()}` };
}

// 节点 5: 发送成功通知 (简单函数节点)
async function sendSuccessEmailNodeFunc(context: INodeContext) {
  const { email, orderId, productId, finalPrice } = context.input;
  const subject = '订单创建成功';
  const body = `您的订单 ${orderId} 已成功创建，商品 ${productId}，价格 ${finalPrice}。`;
  context.log(`发送成功邮件给 ${email}`);
  // 实际应调用 sendEmailService
  await new Promise(res => setTimeout(res, 40));
  // 可以在这里设置 output 表示发送成功
}

// 节点 6: 发送失败通知 (简单函数节点)
async function sendFailureEmailNodeFunc(context: INodeContext) {
  const { email, productId, reason } = context.input;
  const subject = '订单创建失败';
  const body = `抱歉，您的订单 (商品 ${productId}) 创建失败。原因: ${reason || '未知错误'}`;
  context.log(`发送失败邮件给 ${email}`);
  // 实际应调用 sendEmailService
  await new Promise(res => setTimeout(res, 40));
}

// 节点 7: 记录库存不足 (简单函数节点)
async function logStockIssueNodeFunc(context: INodeContext) {
    const productId = context.input.productId;
    const stock = context.input.stock;
    const message = `商品 ${productId} 库存不足 (${stock})，订单无法创建。`;
    context.log(message);
    // 可以将原因设置到变量，用于后续的失败通知
    context.setVariable('failureReason', message);
    // 这个节点本身是成功的，但它会导致流程走向失败路径
}


// ---------- 初始化 FlowLab 引擎并注册节点 ----------
const engine = new FlowLabEngine();

engine.registerNode(new FetchUserNode()); // 注册类节点
engine.registerNode('fetch-product', fetchProductNodeFunc, '获取商品信息'); // 注册函数节点
engine.registerNode('calculate-price', calculatePriceNodeFunc, '计算最终价格');
engine.registerNode('create-order', createOrderNodeFunc, '调用订单服务创建订单');
engine.registerNode('send-success-email', sendSuccessEmailNodeFunc, '发送成功通知邮件');
engine.registerNode('send-failure-email', sendFailureEmailNodeFunc, '发送失败通知邮件');
engine.registerNode('log-stock-issue', logStockIssueNodeFunc, '记录库存不足信息');

// ---------- 定义工作流 ----------
const orderWorkflow = engine.defineWorkflow('order-processing', '订单处理与通知流程')
  .addParallel({ // 步骤 1 & 2: 并行获取用户和商品信息
    id: 'fetch-data',
    parallelSteps: [
      { // 并行分支 1: 获取用户
        id: 'fetch-user-step', // 并行分支内的步骤也需要 ID (虽然通常不直接引用)
        type: StepType.TASK, // 需要显式指定类型
        nodeId: 'fetch-user',
        inputMapping: { 'userId': 'input.userId' },
        outputMapping: { 'variables.userInfo': 'output' }, // 将整个用户信息存入变量
        retryOptions: { maxRetries: 2, delayMs: 100 } // 在步骤级别配置重试
      },
      { // 并行分支 2: 获取商品
        id: 'fetch-product-step',
        type: StepType.TASK,
        nodeId: 'fetch-product',
        inputMapping: { 'productId': 'input.productId' },
        outputMapping: { 'variables.productInfo': 'output' }, // 将整个商品信息存入变量
        retryOptions: { maxRetries: 2, delayMs: 100 } // 配置重试
      }
    ],
    nextStepId: 'check-stock' // 所有并行步骤成功后，进入库存检查
  })
  .addCondition({ // 步骤 3: 检查库存
    id: 'check-stock',
    condition: (context) => (context.variables.productInfo?.stock ?? 0) > 0, // 检查变量中的库存
    branches: {
      'true': 'calculate-price', // 库存充足，去计算价格
      'false': 'log-stock-issue' // 库存不足，记录问题
    }
  })
  .addStep({ // 步骤 4 (库存不足路径): 记录库存问题
      id: 'log-stock-issue',
      nodeId: 'log-stock-issue',
      inputMapping: { // 将商品信息传给日志节点
          'productId': 'variables.productInfo.productId',
          'stock': 'variables.productInfo.stock',
      },
      nextStepId: 'notify-failure' // 记录后直接去发送失败通知
  })
  .addStep({ // 步骤 5 (库存充足路径): 计算价格
    id: 'calculate-price',
    nodeId: 'calculate-price',
    inputMapping: { // 从变量中获取价格和 VIP 等级
      'price': 'variables.productInfo.price',
      'vipLevel': 'variables.userInfo.vipLevel',
    },
    outputMapping: { // 将计算出的最终价格存入变量
      'variables.finalPrice': 'output.finalPrice'
    },
    nextStepId: 'create-order' // 下一步创建订单
  })
  .addStep({ // 步骤 6: 创建订单
    id: 'create-order',
    nodeId: 'create-order',
    inputMapping: { // 从变量和输入中获取所需信息
      'userId': 'variables.userInfo.userId',
      'productId': 'variables.productInfo.productId',
      'price': 'variables.finalPrice'
    },
    outputMapping: { // 将订单 ID 存入变量
      'variables.orderId': 'output.orderId'
    },
    retryOptions: { maxRetries: 1, delayMs: 200 }, // 配置重试
    nextStepId: 'notify-success' // 成功则发送成功通知
    // 注意：如果此步骤失败，默认会使整个工作流失败 (除非配置了错误处理分支或补偿)
  })
  .addStep({ // 步骤 7a (成功路径): 发送成功通知
    id: 'notify-success',
    nodeId: 'send-success-email',
    inputMapping: { // 从变量中获取所需信息
      'email': 'variables.userInfo.email',
      'orderId': 'variables.orderId',
      'productId': 'variables.productInfo.productId',
      'finalPrice': 'variables.finalPrice'
    }
    // 流程结束
  })
  .addStep({ // 步骤 7b (失败路径, 从 log-stock-issue 或 create-order 失败后跳转过来 - 需要错误处理配置实现)
      // 为了简化，我们假设从 log-stock-issue 直接跳过来
      id: 'notify-failure',
      nodeId: 'send-failure-email',
      inputMapping: {
          'email': 'variables.userInfo.email', // 假设 userInfo 总是能获取到
          'productId': 'input.productId',      // 从初始输入获取
          'reason': 'variables.failureReason' // 从 log-stock-issue 设置的变量获取原因
      }
      // 流程结束
  })
  .setStartStep('fetch-data'); // 设置起始步骤

// (可选) 注册定义，以便按 ID 执行
engine.registerDefinition(orderWorkflow);

// ---------- 执行工作流 ----------
async function runFlowLabExample() {
  const executor = engine.createExecutor();
  const initialData = { userId: 'user1', productId: 'productA' };

  console.log(`\n--- 使用 FlowLab 执行订单处理: 用户 ${initialData.userId}, 商品 ${initialData.productId} ---`);
  const resultContext = await executor.run(orderWorkflow, initialData); // 直接用实例执行

  console.log(`\n--- FlowLab 工作流执行完毕 ---`);
  console.log(`最终状态: ${resultContext.status}`);
  console.log(`最终变量:`, resultContext.variables);
  // 可以查看 resultContext.history 获取详细步骤记录
}

runFlowLabExample();