import { ToolManager } from './ToolManager';
import { ActionLoop, ActionLoopStep, ActionLoopOptions, ActionLoopPlugin, ILogger } from './types';
import { ExecutionState } from './types/execution';
import { IAIProvider } from './types/provider';

export class ActionLoopImpl implements ActionLoop {
  private steps: ActionLoopStep[] = [];
  private plugins: ActionLoopPlugin[] = [];
  private provider: IAIProvider;
  private tools: ToolManager;
  private logger: ILogger;
  private options: ActionLoopOptions;

  constructor(options: ActionLoopOptions & {
    provider: IAIProvider;
    tools: ToolManager;
    logger: ILogger;
  }) {
    this.provider = options.provider;
    this.tools = options.tools;
    this.logger = options.logger;
    this.options = {
      maxIterations: options.maxIterations || 10,
      timeoutMs: options.timeoutMs || 30000,
    };
  }

  async execute(initialState: ExecutionState): Promise<ExecutionState> {
    let currentState = initialState;
    let iteration = 0;

    const startTime = Date.now();

    while (iteration < this.options.maxIterations!) {
      if (Date.now() - startTime > this.options.timeoutMs!) {
        throw new Error('Action loop execution timed out');
      }

      await this.notifyPlugins('onBeforeStep', currentState);

      for (const step of this.steps) {
        currentState = await step.execute(currentState);
      }

      await this.notifyPlugins('onAfterStep', currentState);

      iteration++;

      if (this.isLoopComplete(currentState)) {
        break;
      }
    }

    await this.notifyPlugins('onLoopComplete', currentState);

    return currentState;
  }

  addStep(step: ActionLoopStep): void {
    this.steps.push(step);
  }

  removeStep(stepName: string): void {
    this.steps = this.steps.filter(step => step.name !== stepName);
  }

  private isLoopComplete(state: ExecutionState): boolean {
    return false;
  }

  private async notifyPlugins(event: keyof ActionLoopPlugin, state: ExecutionState): Promise<void> {
    for (const plugin of this.plugins) {
      if (plugin[event]) {
        await (plugin[event] as Function)(state);
      }
    }
  }
}