import { Action, ActionSchema } from '../types/tool';
import { PromptDefinition } from '../types/common';
import { ExtendedActionContext, PromptActionConfig, Route } from './types';
import { ChatMessage, ChatOptions } from '../types/chat';
import { evaluateCondition } from '../utils/conditionEvaluator';


export async function executePromptAction<I, O>(
  promptAction: PromptAction<I, O>,
  params: I,
  context: ExtendedActionContext
): Promise<O> {
  if (promptAction.routing && promptAction.routing.length > 0) {
    for (const route of promptAction.routing) {
      if (evaluateCondition(route.condition, { ...context.state, ...params })) {
        if (typeof route.prompt === 'string') {
          return context.executeAction!(route.prompt) as Promise<O>;
        } else {
          return executePromptAction(route.prompt, params, context);
        }
      }
    }
    // If no conditions are met, end execution
    return null as unknown as O;
  }

  // Execute the current prompt if no routing or no conditions met
  const messages: ChatMessage[] = [
    { role: 'system', content: promptAction.content },
    { role: 'user', content: JSON.stringify(params) }
  ];

  const options: ChatOptions = {
    ...promptAction.options,
    ...promptAction.config
  };

  try {
    const result = await context.aiProvider.chat(messages, options);
    return result as O;
  } catch (error) {
    context.logger.error('Error executing prompt action:', error);
    throw error;
  }
}

// Export a test function to verify routing
export function testPromptRouting(promptAction: PromptAction<any, any>, params: any, context: ExtendedActionContext): string {
  let result = 'Routing Test:\n';
  
  if (promptAction.routing && promptAction.routing.length > 0) {
    for (const route of promptAction.routing) {
      const conditionMet = evaluateCondition(route.condition, { ...context.state, ...params });
      result += `Condition "${route.condition}": ${conditionMet ? 'Met' : 'Not Met'}\n`;
      
      if (conditionMet) {
        result += `Routing to: ${typeof route.prompt === 'string' ? route.prompt : route.prompt.name}\n`;
        break;
      }
    }
  } else {
    result += 'No routing defined. Executing current prompt.\n';
  }
  
  return result;
}

export class PromptAction<I, O> implements Action<I, O> {
  name: string;
  content: string;
  options?: ChatOptions;
  routing?: Route[];
  description: string;
  schema: ActionSchema<I, O>;
  priority?: number;
  config?: PromptDefinition['config'];

  constructor({
    name,
    schema,
    systemContent,
    userContent,
    options,
    routing,
    description,
    priority,
    config
  }: PromptActionConfig) {
    this.name = name;
    this.schema = schema as ActionSchema<I, O>;
    this.content = `${systemContent}\n\n${userContent}. Format your response as a RAW JSON object with NO codeblocks. Use format:${JSON.stringify(
      schema.output
    )}`;
    this.options = options;
    this.routing = routing;
    this.description = description || '';
    this.priority = priority;
    this.config = config;
  }

  async execute(params: I, context: ExtendedActionContext): Promise<O> {
    return executePromptAction(this, params, context);
  }

  getPriority(): number | undefined {
    return this.priority;
  }

  setPriority(priority: number): void {
    this.priority = priority;
  }

  getConfig(): PromptDefinition['config'] | undefined {
    return this.config;
  }

  setConfig(config: PromptDefinition['config']): void {
    this.config = config;
  }
}
