import { IStepConfig, StepType, IWorkflowContext, NodeStatus } from '../types/index.js';
import { Step } from './step.js';
import { v4 as uuidv4 } from 'uuid';

/**
 * MARK: 工作流定义
 * @class WorkflowDefinition
 * @description 定义一个工作流的结构和步骤
 */
export class WorkflowDefinition {
  public readonly id: string; // 工作流定义的唯一 ID
  public readonly name?: string; // 工作流名称 (可选)
  public readonly description?: string; // 工作流描述 (可选)
  private steps: Map<string, Step> = new Map(); // 存储所有步骤，以 ID 为键
  private startStepId?: string; // 工作流的起始步骤 ID

  constructor(id: string, name?: string, description?: string) {
    this.id = id || uuidv4(); // 如果未提供 ID，则生成一个
    this.name = name;
    this.description = description;
  }

  /**
   * MARK: addStep
   * 添加一个顺序执行的任务节点步骤
   * @param config - 步骤配置 (必须包含 id, type=TASK, nodeId)
   * @returns 返回 WorkflowDefinition 实例，支持链式调用
   * @throws 如果步骤 ID 重复，则抛出错误
   */
  addStep(config: Omit<IStepConfig, 'type'> & { nodeId: string }): this {
    const fullConfig: IStepConfig = { ...config, type: StepType.TASK };
    return this.addStepInternal(fullConfig);
  }

  /**
   * MARK: 添加条件步骤
   * 添加一个条件分支步骤
   * @param config - 步骤配置 (必须包含 id, type=CONDITION, condition, branches)
   * @returns 返回 WorkflowDefinition 实例，支持链式调用
   */
  addConditionStep(config: Omit<IStepConfig, 'type'> & { condition: (context: IWorkflowContext) => boolean | string; branches: { [key: string]: string } }): this {
      const fullConfig: IStepConfig = { ...config, type: StepType.CONDITION };
      return this.addStepInternal(fullConfig);
  }

  /**
   * MARK: 添加并行步骤
   * 添加一个并行执行步骤
   * @param config - 步骤配置 (必须包含 id, type=PARALLEL, parallelSteps)
   * @returns 返回 WorkflowDefinition 实例，支持链式调用
   */
  addParallelStep(config: Omit<IStepConfig, 'type'> & { parallelSteps: IStepConfig[] }): this {
      const fullConfig: IStepConfig = { ...config, type: StepType.PARALLEL };
      // 可以在这里递归验证 parallelSteps 内部的配置
      return this.addStepInternal(fullConfig);
  }

  /**
   * MARK: 添加子工作流
   * 添加一个子工作流步骤
   * @param config - 步骤配置 (必须包含 id, type=SUB_WORKFLOW, subWorkflowId)
   * @returns 返回 WorkflowDefinition 实例，支持链式调用
   */
  addSubWorkflowStep(config: Omit<IStepConfig, 'type'> & { subWorkflowId: string }): this {
      const fullConfig: IStepConfig = { ...config, type: StepType.SUB_WORKFLOW };
      return this.addStepInternal(fullConfig);
  }

  /**
   * MARK: 添加事件触发
   * 添加一个事件触发步骤
   * @param config - 步骤配置 (必须包含 id, type=EVENT_TRIGGER, event)
   * @returns 返回 WorkflowDefinition 实例，支持链式调用
   */
  addEventTriggerStep(config: Omit<IStepConfig, 'type'> & { event: string }): this {
      const fullConfig: IStepConfig = { ...config, type: StepType.EVENT_TRIGGER };
      return this.addStepInternal(fullConfig);
  }

   /**
    * MARK: 添加事件监听
    * 添加一个事件监听步骤 (通常作为起始步骤或并行分支)
    * @param config - 步骤配置 (必须包含 id, type=EVENT_LISTENER, event)
    * @returns 返回 WorkflowDefinition 实例，支持链式调用
    */
    addEventListenerStep(config: Omit<IStepConfig, 'type'> & { event: string }): this {
        const fullConfig: IStepConfig = { ...config, type: StepType.EVENT_LISTENER };
        return this.addStepInternal(fullConfig);
    }


  /**
   * MARK: addStepInternal
   * NOTE: 内部方法，用于添加步骤并进行基本验证
   * @param config - 完整的步骤配置
   * @returns 返回 WorkflowDefinition 实例
   */
  addStepInternal(config: IStepConfig): this {
    if (this.steps.has(config.id)) {
      throw new Error(`工作流 "${this.id}" 中已存在 ID 为 "${config.id}" 的步骤。`);
    }
    const step = new Step(config);
    this.steps.set(step.id, step);

    // 如果是第一个添加的步骤，则设为起始步骤 (除非是事件监听器)
    if (!this.startStepId && step.type !== StepType.EVENT_LISTENER) {
      this.startStepId = step.id;
    }
    return this;
  }

  /**
   * MARK: setStartStep
   * 设置工作流的起始步骤 ID
   * @param stepId - 起始步骤的 ID
   * @returns 返回 WorkflowDefinition 实例
   * @throws 如果步骤 ID 不存在，则抛出错误
   */
  setStartStep(stepId: string): this {
    if (!this.steps.has(stepId)) {
      throw new Error(`工作流 "${this.id}" 中不存在 ID 为 "${stepId}" 的步骤。`);
    }
    this.startStepId = stepId;
    return this;
  }

  /**
   * MARK: getStartStepId
   * 获取起始步骤 ID
   * @returns 起始步骤 ID
   * @throws 如果未设置起始步骤，则抛出错误
   */
  getStartStepId(): string {
    if (!this.startStepId) {
      throw new Error(`工作流 "${this.id}" 未设置起始步骤。`);
    }
    return this.startStepId;
  }

  /**
   * MARK: getStepById
   * 根据 ID 获取步骤实例
   * @param stepId - 步骤 ID
   * @returns 返回步骤实例，如果未找到则返回 undefined
   */
  getStep(stepId: string): Step | undefined {
    return this.steps.get(stepId);
  }

  /**
   * MARK: getSteps
   * 获取所有步骤的 Map
   */
  getSteps(): Map<string, Step> {
    return this.steps;
  }

  /**
   * MARK: validate
   * 验证工作流定义的有效性 (例如，检查链接是否断开，是否存在循环等)
   * @returns 如果有效则返回 true，否则返回 false 或抛出错误
   */
  validate(): boolean {
    if (!this.startStepId) {
      console.error(`[Workflow: ${this.id}] 验证失败：未设置起始步骤。`);
      return false;
    }
    if (!this.steps.has(this.startStepId)) {
        console.error(`[Workflow: ${this.id}] 验证失败：起始步骤 "${this.startStepId}" 不存在。`);
        return false;
    }

    // TODO: 实现更复杂的验证逻辑
    // 1. 检查所有 nextStepId, branch targets, subWorkflowId 是否指向存在的步骤/工作流
    // 2. 检查是否存在无法到达的步骤
    // 3. (可选) 检测简单循环 (复杂的循环检测可能需要图算法)
    // 4. 检查并行步骤的配置是否正确
    // 5. 检查 TASK 步骤是否关联了已注册的 nodeId

    console.log(`[Workflow: ${this.id}] 验证通过 (基本检查)。`);
    return true;
  }
}