/**
 * Workflow execution context — a shared data store that flows between nodes.
 * Each node can read from context and write its output back.
 */
export class ExecutionContext {
  private data: Record<string, any>;

  constructor(initialData: Record<string, any> = {}) {
    this.data = { ...initialData };
  }

  /** Get a value by dot-notation path (e.g. "node1.data.email") */
  get(path: string): any {
    const parts = path.split('.');
    let current: any = this.data;
    for (const part of parts) {
      if (current == null) return undefined;
      current = current[part];
    }
    return current;
  }

  /** Set a value by key */
  set(key: string, value: any): void {
    this.data[key] = value;
  }

  /** Merge node output into context under the node's ID */
  mergeNodeOutput(nodeId: string, output: Record<string, any>): void {
    this.data[nodeId] = output;
  }

  /** Get the full context object */
  toJSON(): Record<string, any> {
    return { ...this.data };
  }

  /** Resolve template strings like "{{node1.data.email}}" within a value */
  resolveTemplates(value: any): any {
    if (typeof value === 'string') {
      return value.replace(/\{\{(.+?)\}\}/g, (_, path) => {
        const resolved = this.get(path.trim());
        return resolved !== undefined ? String(resolved) : '';
      });
    }
    if (Array.isArray(value)) {
      return value.map((v) => this.resolveTemplates(v));
    }
    if (value && typeof value === 'object') {
      const result: Record<string, any> = {};
      for (const [k, v] of Object.entries(value)) {
        result[k] = this.resolveTemplates(v);
      }
      return result;
    }
    return value;
  }
}
