/**
 * This file is part of the NocoBase (R) project.
 * Copyright (c) 2020-2024 NocoBase Co., Ltd.
 * Authors: NocoBase Team.
 *
 * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
 * For more information, please refer to: https://www.nocobase.com/agreement.
 */

import { action, autorun, define, observable, observe } from '@formily/reactive';
import _ from 'lodash';
import React from 'react';
import { uid } from 'uid/secure';
import { openRequiredParamsStepFormDialog as openRequiredParamsStepFormDialogFn } from '../components/settings/wrappers/contextual/StepRequiredSettingsDialog';
import { openStepSettingsDialog as openStepSettingsDialogFn } from '../components/settings/wrappers/contextual/StepSettingsDialog';
import { Emitter } from '../emitter';
import { FlowEngine } from '../flowEngine';
import type {
  ArrayElementType,
  CreateModelOptions,
  CreateSubModelOptions,
  DefaultStructure,
  FlowContext,
  FlowDefinition,
  FlowModelMeta,
  FlowModelOptions,
  ParentFlowModel,
  StepDefinition,
  StepParams,
} from '../types';
import { ExtendedFlowDefinition, FlowExtraContext, IModelComponentProps, ReadonlyModelProps } from '../types';
import { FlowExitException, generateUid, mergeFlowDefinitions, resolveDefaultParams } from '../utils';
import { ForkFlowModel } from './forkFlowModel';

// 使用WeakMap存储每个类的meta
const modelMetas = new WeakMap<typeof FlowModel, FlowModelMeta>();

// 使用WeakMap存储每个类的flows
const modelFlows = new WeakMap<typeof FlowModel, Map<string, FlowDefinition>>();

export class FlowModel<Structure extends DefaultStructure = DefaultStructure> {
  public readonly uid: string;
  public sortIndex: number;
  public props: IModelComponentProps = {};
  public stepParams: StepParams = {};
  public flowEngine: FlowEngine;
  public parent: ParentFlowModel<Structure>;
  public subModels: Structure['subModels'];
  private _options: FlowModelOptions<Structure>;

  /**
   * 所有 fork 实例的引用集合。
   * 使用 Set 便于在销毁时主动遍历并调用 dispose，避免悬挂引用。
   */
  public forks: Set<ForkFlowModel<any>> = new Set();
  public emitter: Emitter = new Emitter();

  /**
   * 基于 key 的 fork 实例缓存，用于复用 fork 实例
   */
  private forkCache: Map<string, ForkFlowModel<any>> = new Map();

  /**
   * model 树的共享运行上下文
   */
  protected _sharedContext: Record<string, any> = {};

  /**
   * 上一次 applyAutoFlows 的执行参数
   */
  private _lastAutoRunParams: any[] | null = null;
  private observerDispose: () => void;

  constructor(options: FlowModelOptions<Structure>) {
    if (!options.flowEngine) {
      throw new Error('FlowModel must be initialized with a FlowEngine instance.');
    }
    this.flowEngine = options.flowEngine;
    if (this.flowEngine.getModel(options.uid)) {
      // 此时 new FlowModel 并不创建新实例，而是返回已存在的实例，避免重复创建同一个model实例
      return this.flowEngine.getModel(options.uid);
    }

    if (!options.uid) {
      options.uid = uid();
    }

    this.uid = options.uid;
    this.props = options.props || {};
    this.stepParams = options.stepParams || {};
    this.subModels = {};
    this.sortIndex = options.sortIndex || 0;
    this._options = options;

    define(this, {
      props: observable,
      subModels: observable.shallow,
      stepParams: observable,
      setProps: action,
      setStepParams: action,
    });
    // 保证onInit在所有属性都定义完成后调用
    // queueMicrotask(() => {
    //   this.onInit(options);
    // });
    this.createSubModels(options.subModels);

    this.observerDispose = observe(this.stepParams, () => {
      if (this.flowEngine) {
        this.clearAutoFlowCache();
      }
      this._rerunLastAutoRun();
    });
  }

  on(eventName: string, listener: (...args: any[]) => void) {
    this.emitter.on(eventName, listener);
  }

  onInit(options) {}

  get async() {
    return this._options.async || false;
  }

  get subKey() {
    return this._options.subKey;
  }

  get reactView() {
    return this.flowEngine.reactView;
  }

  static get meta() {
    return modelMetas.get(this);
  }

  private createSubModels(subModels: Record<string, CreateSubModelOptions | CreateSubModelOptions[]>) {
    Object.entries(subModels || {}).forEach(([key, value]) => {
      if (Array.isArray(value)) {
        value
          .sort((a, b) => (a.sortIndex || 0) - (b.sortIndex || 0))
          .forEach((item) => {
            this.addSubModel(key, item);
          });
      } else {
        this.setSubModel(key, value);
      }
    });
  }

  private clearAutoFlowCache() {
    if (this.flowEngine) {
      const cacheKey = FlowEngine.generateApplyFlowCacheKey('autoFlow', 'all', this.uid);
      this.flowEngine.applyFlowCache.delete(cacheKey);
      this.forks.forEach((fork) => {
        const forkCacheKey = FlowEngine.generateApplyFlowCacheKey(`${fork['forkId']}`, 'all', this.uid);
        this.flowEngine.applyFlowCache.delete(forkCacheKey);
      });
    }
  }

  /**
   * 设置FlowEngine实例
   * @param {FlowEngine} flowEngine FlowEngine实例
   */
  setFlowEngine(flowEngine: FlowEngine): void {
    // this.flowEngine = flowEngine;
  }

  static define(meta: FlowModelMeta) {
    modelMetas.set(this, meta);
  }

  /**
   * 注册一个流程 (Flow)。支持泛型，能够正确推导出模型类型。
   * @template TModel 具体的FlowModel子类类型
   * @param {string | FlowDefinition<TModel>} keyOrDefinition 流程的 Key 或 FlowDefinition 对象。
   *        如果为字符串，则为流程 Key，需要配合 flowDefinition 参数。
   *        如果为对象，则为包含 key 属性的完整 FlowDefinition。
   * @param {FlowDefinition<TModel>} [flowDefinition] 当第一个参数为流程 Key 时，此参数为流程的定义。
   * @returns {void}
   */
  public static registerFlow<TModel extends new (...args: any[]) => FlowModel<any>>(
    this: TModel,
    keyOrDefinition: string | FlowDefinition<InstanceType<TModel>>,
    flowDefinition?: Omit<FlowDefinition<InstanceType<TModel>>, 'key'> & { key?: string },
  ): void {
    let definition: FlowDefinition<InstanceType<TModel>>;
    let key: string;

    if (typeof keyOrDefinition === 'string' && flowDefinition) {
      key = keyOrDefinition;
      definition = {
        ...flowDefinition,
        key,
      };
    } else if (typeof keyOrDefinition === 'object' && 'key' in keyOrDefinition) {
      key = keyOrDefinition.key;
      definition = keyOrDefinition;
    } else {
      throw new Error('Invalid arguments for registerFlow');
    }

    // 确保当前类有自己的flows Map
    const ModelClass = this;
    if (!modelFlows.has(ModelClass as any)) {
      modelFlows.set(ModelClass as any, new Map<string, FlowDefinition>());
    }
    const flows = modelFlows.get(ModelClass as any)!;

    if (flows.has(key)) {
      console.warn(`FlowModel: Flow with key '${key}' is already registered and will be overwritten.`);
    }
    flows.set(key, definition as FlowDefinition);
  }

  /**
   * 扩展已存在的流程定义。通过合并现有流程和扩展定义来创建新的流程。
   * @template TModel 具体的FlowModel子类类型
   * @param {string | ExtendedFlowDefinition} keyOrDefinition 流程的 Key 或 ExtendedFlowDefinition 对象。
   *        如果为字符串，则为流程 Key，需要配合 extendDefinition 参数。
   *        如果为对象，则为包含 key 属性的完整 ExtendedFlowDefinition。
   * @param {Omit<ExtendedFlowDefinition, 'key'>} [extendDefinition] 当第一个参数为流程 Key 时，此参数为流程的扩展定义。
   * @returns {void}
   */
  public static extendFlow<TModel extends FlowModel = FlowModel>(
    keyOrDefinition: string | ExtendedFlowDefinition,
    extendDefinition?: Omit<ExtendedFlowDefinition, 'key'>,
  ): void {
    let definition: ExtendedFlowDefinition;
    let key: string;

    if (typeof keyOrDefinition === 'string' && extendDefinition) {
      key = keyOrDefinition;
      definition = {
        ...extendDefinition,
        key,
      };
    } else if (typeof keyOrDefinition === 'object' && 'key' in keyOrDefinition) {
      key = keyOrDefinition.key;
      definition = keyOrDefinition;
    } else {
      throw new Error('Invalid arguments for extendFlow');
    }

    // 获取所有流程（包括从父类继承的）
    const allFlows = this.getFlows();
    const originalFlow = allFlows.get(key);

    if (!originalFlow) {
      console.warn(
        `FlowModel.extendFlow: Cannot extend flow '${key}' as it does not exist in parent class. Registering as new flow.`,
      );
      // 移除patch标记，作为新流程注册
      const { patch, ...newFlowDef } = definition;
      this.registerFlow(newFlowDef as FlowDefinition<TModel>);
      return;
    }

    // 合并流程定义
    const mergedFlow = mergeFlowDefinitions(originalFlow, definition);

    // 注册合并后的流程
    this.registerFlow(mergedFlow as FlowDefinition<TModel>);
  }

  /**
   * 获取已注册的流程定义。
   * 如果当前类不存在对应的flow，会继续往父类查找。
   * @param {string} key 流程 Key。
   * @returns {FlowDefinition | undefined} 流程定义，如果未找到则返回 undefined。
   */
  public getFlow(key: string): FlowDefinition | undefined {
    // 获取当前类的构造函数
    const currentClass = this.constructor as typeof FlowModel;

    // 遍历类继承链，查找流程
    let cls: typeof FlowModel | null = currentClass;
    while (cls) {
      const flows = modelFlows.get(cls);
      if (flows && flows.has(key)) {
        return flows.get(key);
      }

      // 获取父类
      const proto = Object.getPrototypeOf(cls);
      if (proto === Function.prototype || proto === Object.prototype) {
        break;
      }
      cls = proto as typeof FlowModel;
    }

    return undefined;
  }

  /**
   * 获取所有已注册的流程定义，包括从父类继承的流程。
   * @returns {Map<string, FlowDefinition>} 一个包含所有流程定义的 Map 对象，Key 为流程 Key，Value 为流程定义。
   */
  public static getFlows(): Map<string, FlowDefinition> {
    // 创建一个新的Map来存储所有流程
    const allFlows = new Map<string, FlowDefinition>();

    // 遍历类继承链，收集所有流程
    let cls: typeof FlowModel | null = this;
    while (cls) {
      const flows = modelFlows.get(cls);
      if (flows) {
        // 合并流程，但如果已有同名流程则不覆盖
        for (const [key, flow] of flows.entries()) {
          if (!allFlows.has(key)) {
            allFlows.set(key, flow);
          }
        }
      }

      // 获取父类
      const proto = Object.getPrototypeOf(cls);
      if (proto === Function.prototype || proto === Object.prototype) {
        break;
      }
      cls = proto as typeof FlowModel;
    }

    return allFlows;
  }

  setProps(props: IModelComponentProps): void;
  setProps(key: string, value: any): void;
  setProps(props: IModelComponentProps | string, value?: any): void {
    if (typeof props === 'string') {
      this.props[props] = value;
    } else {
      this.props = { ...this.props, ...props };
    }
  }

  getProps(): ReadonlyModelProps {
    return this.props as ReadonlyModelProps;
  }

  setStepParams(flowKey: string, stepKey: string, params: any): void;
  setStepParams(flowKey: string, stepParams: Record<string, any>): void;
  setStepParams(allParams: StepParams): void;
  setStepParams(
    flowKeyOrAllParams: string | StepParams,
    stepKeyOrStepsParams?: string | Record<string, any>,
    params?: any,
  ): void {
    if (typeof flowKeyOrAllParams === 'string') {
      const flowKey = flowKeyOrAllParams;
      if (typeof stepKeyOrStepsParams === 'string' && params !== undefined) {
        if (!this.stepParams[flowKey]) {
          this.stepParams[flowKey] = {};
        }
        this.stepParams[flowKey][stepKeyOrStepsParams] = {
          ...this.stepParams[flowKey][stepKeyOrStepsParams],
          ...params,
        };
      } else if (typeof stepKeyOrStepsParams === 'object' && stepKeyOrStepsParams !== null) {
        this.stepParams[flowKey] = { ...(this.stepParams[flowKey] || {}), ...stepKeyOrStepsParams };
      }
    } else if (typeof flowKeyOrAllParams === 'object' && flowKeyOrAllParams !== null) {
      for (const fk in flowKeyOrAllParams) {
        if (Object.prototype.hasOwnProperty.call(flowKeyOrAllParams, fk)) {
          this.stepParams[fk] = { ...(this.stepParams[fk] || {}), ...flowKeyOrAllParams[fk] };
        }
      }
    }
  }

  getStepParams(flowKey: string, stepKey: string): any | undefined;
  getStepParams(flowKey: string): Record<string, any> | undefined;
  getStepParams(): StepParams;
  getStepParams(flowKey?: string, stepKey?: string): any {
    if (flowKey && stepKey) {
      return this.stepParams[flowKey]?.[stepKey];
    }
    if (flowKey) {
      return this.stepParams[flowKey];
    }
    return this.stepParams;
  }

  async applyFlow(flowKey: string, extra?: FlowExtraContext): Promise<any> {
    const currentFlowEngine = this.flowEngine;
    if (!currentFlowEngine) {
      console.warn('FlowEngine not available on this model for applyFlow. Check and model.flowEngine setup.');
      return Promise.reject(new Error('FlowEngine not available for applyFlow. Please set flowEngine on the model.'));
    }

    const flow = this.getFlow(flowKey);

    if (!flow) {
      console.error(`BaseModel.applyFlow: Flow with key '${flowKey}' not found.`);
      return Promise.reject(new Error(`Flow '${flowKey}' not found.`));
    }

    let lastResult: any;
    const stepResults: Record<string, any> = {};

    // Create a new FlowContext instance for this flow execution
    const createLogger = (level: string) => (message: string, meta?: any) => {
      const logMessage = `[${level.toUpperCase()}] [Flow: ${flowKey}] [Model: ${this.uid}] ${message}`;
      const logMeta = { flowKey, modelUid: this.uid, ...meta };
      console[level.toLowerCase()](logMessage, logMeta);
    };

    const globalContexts = currentFlowEngine.getContext();
    const flowContext: FlowContext<this> = {
      exit: () => {
        throw new FlowExitException(flowKey, this.uid);
      },
      logger: {
        info: createLogger('INFO'),
        warn: createLogger('WARN'),
        error: createLogger('ERROR'),
        debug: createLogger('DEBUG'),
      },
      reactView: this.reactView,
      stepResults,
      shared: this.getSharedContext(),
      globals: globalContexts,
      extra: extra || {},
      model: this,
      app: globalContexts.app || {},
    };

    for (const stepKey in flow.steps) {
      if (Object.prototype.hasOwnProperty.call(flow.steps, stepKey)) {
        const step: StepDefinition = flow.steps[stepKey];
        let handler: ((ctx: FlowContext<this>, params: any) => Promise<any> | any) | undefined;
        let combinedParams: Record<string, any> = {};
        let actionDefinition;

        if (step.use) {
          // Step references a registered action
          actionDefinition = currentFlowEngine.getAction(step.use);
          if (!actionDefinition) {
            console.error(
              `BaseModel.applyFlow: Action '${step.use}' not found for step '${stepKey}' in flow '${flowKey}'. Skipping.`,
            );
            continue;
          }
          // Use step's handler if provided, otherwise use action's handler
          handler = step.handler || actionDefinition.handler;
          // Merge default params: action defaults first, then step defaults
          const actionDefaultParams = await resolveDefaultParams(actionDefinition.defaultParams, flowContext);
          const stepDefaultParams = await resolveDefaultParams(step.defaultParams, flowContext);
          combinedParams = { ...actionDefaultParams, ...stepDefaultParams };
        } else if (step.handler) {
          // Step defines its own inline handler
          handler = step.handler;
          const stepDefaultParams = await resolveDefaultParams(step.defaultParams, flowContext);
          combinedParams = { ...stepDefaultParams };
        } else {
          console.error(
            `BaseModel.applyFlow: Step '${stepKey}' in flow '${flowKey}' has neither 'use' nor 'handler'. Skipping.`,
          );
          continue;
        }

        const modelStepParams = this.getStepParams(flowKey, stepKey);
        if (modelStepParams !== undefined) {
          combinedParams = { ...combinedParams, ...modelStepParams };
        }

        try {
          const currentStepResult = handler!(flowContext, combinedParams);
          if (step.isAwait !== false) {
            lastResult = await currentStepResult;
          } else {
            lastResult = currentStepResult;
          }

          // Store step result
          stepResults[stepKey] = lastResult;
        } catch (error) {
          // 检查是否是通过 ctx.exit() 正常退出
          if (error instanceof FlowExitException) {
            console.log(`[FlowEngine] ${error.message}`);
            return Promise.resolve(stepResults);
          }

          console.error(`BaseModel.applyFlow: Error executing step '${stepKey}' in flow '${flowKey}':`, error);
          return Promise.reject(error);
        }
      }
    }
    return Promise.resolve(stepResults);
  }

  dispatchEvent(eventName: string, extra?: FlowExtraContext): void {
    const currentFlowEngine = this.flowEngine;
    if (!currentFlowEngine) {
      console.warn('FlowEngine not available on this model for dispatchEvent. Please set flowEngine on the model.');
      return;
    }

    // 获取所有流程
    const constructor = this.constructor as typeof FlowModel;
    const allFlows = constructor.getFlows();

    allFlows.forEach((flow) => {
      if (flow.on && flow.on.eventName === eventName) {
        console.log(`BaseModel '${this.uid}' dispatching event '${eventName}' to flow '${flow.key}'.`);
        this.applyFlow(flow.key, extra).catch((error) => {
          console.error(
            `BaseModel.dispatchEvent: Error executing event-triggered flow '${flow.key}' for event '${eventName}':`,
            error,
          );
        });
      }
    });
  }

  /**
   * 创建一个新的 FlowModel 子类，并预注册指定的流程。
   * @param {ExtendedFlowDefinition[]} flows 要预注册的流程定义数组
   *        如果flow.patch为true，则表示这是对父类同名流程的部分覆盖
   * @returns 新创建的 FlowModel 子类
   */
  public static extends<T extends typeof FlowModel>(this: T, flows: ExtendedFlowDefinition[] = []): T {
    class CustomFlowModel extends (this as unknown as typeof FlowModel) {
      // @ts-ignore
      static name = `CustomFlowModel_${generateUid()}`;
    }

    // 处理流程注册和覆盖
    if (flows.length > 0) {
      flows.forEach((flowDefinition) => {
        // 如果标记为部分覆盖，则调用extendFlow方法
        if (flowDefinition.patch === true) {
          CustomFlowModel.extendFlow(flowDefinition);
        } else {
          // 完全覆盖或新增流程
          CustomFlowModel.registerFlow(flowDefinition as FlowDefinition);
        }
      });
    }

    return CustomFlowModel as unknown as T;
  }

  /**
   * 获取所有自动应用流程定义并按 sort 排序
   * @returns {FlowDefinition[]} 按 sort 排序的自动应用流程定义数组
   */
  public getAutoFlows(): FlowDefinition[] {
    const constructor = this.constructor as typeof FlowModel;
    const allFlows = constructor.getFlows();

    // 过滤出自动流程并按 sort 排序
    const autoFlows = Array.from(allFlows.values())
      .filter((flow) => flow.auto === true)
      .sort((a, b) => (a.sort || 0) - (b.sort || 0));

    return autoFlows;
  }

  /**
   * 重新执行上一次的 applyAutoFlows，保持参数一致
   * 如果之前没有执行过，则直接跳过
   * 使用 lodash debounce 避免频繁调用
   */
  private _rerunLastAutoRun = _.debounce(async () => {
    if (this._lastAutoRunParams) {
      try {
        await this.applyAutoFlows(...this._lastAutoRunParams);
      } catch (error) {
        console.error('FlowModel._rerunLastAutoRun: Error during rerun:', error);
      }
    }
  }, 100);

  /**
   * 执行所有自动应用流程
   * @param {FlowExtraContext} [extra] 可选的额外上下文
   * @param {boolean} [useCache=true] 是否使用缓存机制，默认为 true
   * @returns {Promise<any[]>} 所有自动应用流程的执行结果数组
   */
  async applyAutoFlows(extra?: FlowExtraContext, useCache?: boolean): Promise<any[]>;
  async applyAutoFlows(...args: any[]): Promise<any[]> {
    const [extra, useCache = true] = args;
    // 生成缓存键，包含 stepParams 的序列化版本以确保参数变化时重新执行
    const cacheKey = useCache
      ? FlowEngine.generateApplyFlowCacheKey(this['forkId'] ?? 'autoFlow', 'all', this.uid)
      : null;

    if (!_.isEqual(extra, this._lastAutoRunParams?.[0]) && cacheKey) {
      this.flowEngine.applyFlowCache.delete(cacheKey);
    }

    // 存储本次执行的参数，用于后续重新执行
    this._lastAutoRunParams = args;

    const autoApplyFlows = this.getAutoFlows();

    if (autoApplyFlows.length === 0) {
      console.warn(`FlowModel: No auto-apply flows found for model '${this.uid}'`);
      return [];
    }

    // 检查缓存
    if (cacheKey && this.flowEngine) {
      const cachedEntry = this.flowEngine.applyFlowCache.get(cacheKey);
      if (cachedEntry) {
        if (cachedEntry.status === 'resolved') {
          console.log(`[FlowEngine.applyAutoFlows] Using cached result for model: ${this.uid}`);
          return cachedEntry.data;
        }
        if (cachedEntry.status === 'rejected') throw cachedEntry.error;
        if (cachedEntry.status === 'pending') return await cachedEntry.promise;
      }
    }

    // 执行 autoFlows
    const executeAutoFlows = async (): Promise<any[]> => {
      const results: any[] = [];
      for (const flow of autoApplyFlows) {
        try {
          const result = await this.applyFlow(flow.key, extra);
          results.push(result);
        } catch (error) {
          console.error(`FlowModel.applyAutoFlows: Error executing auto-apply flow '${flow.key}':`, error);
          throw error;
        }
      }
      return results;
    };

    // 如果不使用缓存，直接执行
    if (!cacheKey || !this.flowEngine) {
      return await executeAutoFlows();
    }

    // 使用缓存机制
    const promise = executeAutoFlows()
      .then((result) => {
        this.flowEngine.applyFlowCache.set(cacheKey, {
          status: 'resolved',
          data: result,
          promise: Promise.resolve(result),
        });
        return result;
      })
      .catch((err) => {
        this.flowEngine.applyFlowCache.set(cacheKey, {
          status: 'rejected',
          error: err,
          promise: Promise.reject(err),
        });
        throw err;
      });

    this.flowEngine.applyFlowCache.set(cacheKey, { status: 'pending', promise });
    return await promise;
  }

  /**
   * Renders the React representation of this flow model.
   * @returns {React.ReactNode} The React node to render.
   */
  public render(): any {
    // console.warn('FlowModel.render() not implemented. Override in subclass for FlowModelRenderer.');
    // 默认返回一个空的div，子类可以覆盖这个方法来实现具体的渲染逻辑
    return <div {...this.props}></div>;
  }

  async rerender() {
    await this.applyAutoFlows(this._lastAutoRunParams?.[0], false);
  }

  setParent(parent: FlowModel): void {
    if (!parent || !(parent instanceof FlowModel)) {
      throw new Error('Parent must be an instance of FlowModel.');
    }
    this.parent = parent as ParentFlowModel<Structure>;
    this._options.parentId = parent.uid;
  }

  addSubModel(subKey: string, options: CreateModelOptions | FlowModel) {
    let model: FlowModel;
    if (options instanceof FlowModel) {
      if (options.parent && options.parent !== this) {
        throw new Error('Sub model already has a parent.');
      }
      model = options;
    } else {
      model = this.flowEngine.createModel({ ...options, subKey, subType: 'array' });
    }
    model.setParent(this);
    const subModels = this.subModels as {
      [subKey: string]: FlowModel[];
    };
    if (!Array.isArray(subModels[subKey])) {
      subModels[subKey] = observable.shallow([]);
    }
    const maxSortIndex = Math.max(...(subModels[subKey] as FlowModel[]).map((item) => item.sortIndex || 0), 0);
    model.sortIndex = maxSortIndex + 1;
    subModels[subKey].push(model);
    this.emitter.emit('onSubModelAdded', model);
    return model;
  }

  setSubModel(subKey: string, options: CreateModelOptions | FlowModel) {
    let model: FlowModel;
    if (options instanceof FlowModel) {
      if (options.parent && options.parent !== this) {
        throw new Error('Sub model already has a parent.');
      }
      model = options;
    } else {
      model = this.flowEngine.createModel({ ...options, parentId: this.uid, subKey, subType: 'object' });
    }
    model.setParent(this);
    (this.subModels as any)[subKey] = model;
    this.emitter.emit('onSubModelAdded', model);
    return model;
  }

  mapSubModels<K extends keyof Structure['subModels'], R>(
    subKey: K,
    callback: (model: ArrayElementType<Structure['subModels'][K]>, index: number) => R,
  ): R[] {
    const model = (this.subModels as any)[subKey as string];

    if (!model) {
      return [];
    }

    const results: R[] = [];

    _.castArray(model).forEach((item, index) => {
      const result = (callback as (model: any, index: number) => R)(item, index);
      results.push(result);
    });

    return results;
  }

  findSubModel<K extends keyof Structure['subModels'], R>(
    subKey: K,
    callback: (model: ArrayElementType<Structure['subModels'][K]>) => R,
  ): ArrayElementType<Structure['subModels'][K]> | null {
    const model = (this.subModels as any)[subKey as string];

    if (!model) {
      return null;
    }

    return (
      (_.castArray(model).find((item) => {
        return (callback as (model: any) => R)(item);
      }) as ArrayElementType<Structure['subModels'][K]> | undefined) || null
    );
  }

  createRootModel(options) {
    return this.flowEngine.createModel(options);
  }

  async applySubModelsAutoFlows<K extends keyof Structure['subModels']>(
    subKey: K,
    extra?: Record<string, any>,
    shared?: Record<string, any>,
  ) {
    await Promise.all(
      this.mapSubModels(subKey, async (sub) => {
        sub.setSharedContext(shared);
        await sub.applyAutoFlows(extra);
      }),
    );
  }

  /**
   * 创建一个 fork 实例，实现"一份数据（master）多视图（fork）"的能力。
   * @param {IModelComponentProps} [localProps={}] fork 专属的局部 props，优先级高于 master.props
   * @param {string} [key] 可选的 key，用于复用 fork 实例。如果提供了 key，会尝试复用已存在的 fork
   * @returns {ForkFlowModel<this>} 创建的 fork 实例
   */
  createFork(localProps?: IModelComponentProps, key?: string): ForkFlowModel<this> {
    // 如果提供了 key，尝试从缓存中获取
    if (key) {
      const cachedFork = this.forkCache.get(key);
      if (cachedFork && !(cachedFork as any).disposed) {
        // 更新 localProps
        cachedFork.setProps(localProps || {});
        return cachedFork as ForkFlowModel<this>;
      }
    }

    // 创建新的 fork 实例
    const forkId = this.forks.size; // 当前集合大小作为索引
    const fork = new ForkFlowModel<this>(this as any, localProps, forkId);
    this.forks.add(fork as any);

    // 如果提供了 key，将 fork 缓存起来
    if (key) {
      this.forkCache.set(key, fork as any);
    }

    return fork as ForkFlowModel<this>;
  }

  clearForks() {
    console.log(`FlowModel ${this.uid} clearing all forks.`);
    // 主动使所有 fork 失效
    if (this.forks?.size) {
      this.forks.forEach((fork) => fork.dispose());
      this.forks.clear();
    }
    // 清理 fork 缓存
    this.forkCache.clear();
  }

  /**
   * 移动当前模型到目标模型的位置
   * @param {FlowModel} targetModel 目标模型
   * @returns {boolean} 是否成功移动
   */
  moveTo(targetModel: FlowModel) {
    if (!this.flowEngine) {
      throw new Error('FlowEngine is not set on this model. Please set flowEngine before saving.');
    }
    return this.flowEngine.moveModel(this.uid, targetModel.uid);
  }

  remove() {
    if (!this.flowEngine) {
      throw new Error('FlowEngine is not set on this model. Please set flowEngine before saving.');
    }
    this.observerDispose();
    return this.flowEngine.removeModel(this.uid);
  }

  async save() {
    if (!this.flowEngine) {
      throw new Error('FlowEngine is not set on this model. Please set flowEngine before saving.');
    }
    return this.flowEngine.saveModel(this);
  }

  async destroy() {
    if (!this.flowEngine) {
      throw new Error('FlowEngine is not set on this model. Please set flowEngine before deleting.');
    }
    this.observerDispose();
    // 从 FlowEngine 中销毁模型
    return this.flowEngine.destroyModel(this.uid);
  }

  /**
   * 打开步骤设置对话框
   * 用于配置流程中特定步骤的参数和设置
   * @param {string} flowKey 流程的唯一标识符
   * @param {string} stepKey 步骤的唯一标识符
   * @returns {void}
   */
  openStepSettingsDialog(flowKey: string, stepKey: string) {
    return openStepSettingsDialogFn({
      model: this,
      flowKey,
      stepKey,
    });
  }

  /**
   * 配置必填步骤参数
   * 用于在一个分步表单中配置所有需要参数的步骤
   * @param {number | string} [dialogWidth=800] 对话框宽度，默认为800
   * @param {string} [dialogTitle='步骤参数配置'] 对话框标题，默认为'步骤参数配置'
   * @returns {Promise<any>} 返回表单提交的值
   */
  async configureRequiredSteps(dialogWidth?: number | string, dialogTitle?: string) {
    return openRequiredParamsStepFormDialogFn({
      model: this,
      dialogWidth,
      dialogTitle,
    });
  }

  get ctx() {
    return {
      globals: this.flowEngine.getContext(),
      shared: this.getSharedContext(),
    };
  }

  get translate() {
    return this.flowEngine.translate.bind(this.flowEngine);
  }

  public setSharedContext(ctx: Record<string, any>) {
    this._sharedContext = { ...this._sharedContext, ...ctx };
  }

  public getSharedContext() {
    if (this.async || !this.parent) {
      return this._sharedContext;
    }
    return {
      ...this.parent?.getSharedContext(),
      ...this._sharedContext, // 当前实例的 context 优先级最高
    };
  }

  // TODO: 不完整，需要考虑 sub-model 的情况
  serialize(): Record<string, any> {
    const data = {
      uid: this.uid,
      ..._.omit(this._options, ['flowEngine']),
      // props: this.props,
      stepParams: this.stepParams,
      sortIndex: this.sortIndex,
    };
    const subModels = this.subModels as {
      [key: string]: FlowModel | FlowModel[];
    };
    for (const subModelKey in subModels) {
      data.subModels = data.subModels || {};
      if (Array.isArray(subModels[subModelKey])) {
        (data.subModels as any)[subModelKey] = (subModels[subModelKey] as FlowModel[]).map((model, index) => ({
          ...model.serialize(),
          sortIndex: index,
        }));
      } else if (subModels[subModelKey] instanceof FlowModel) {
        (data.subModels as any)[subModelKey] = (subModels[subModelKey] as FlowModel).serialize();
      }
    }
    return data;
  }
}

export function defineFlow<TModel extends FlowModel = FlowModel>(definition: FlowDefinition): FlowDefinition<TModel> {
  return definition as FlowDefinition<TModel>;
}
