import { readFileSync, existsSync } from 'fs';
import { ToolError } from './errors';
import { AIProvider } from './providers/anthropic';
import { loadConfig } from './config';

export interface Variation {
  system?: string;
  model?: string;
  prompt?: string;
}

export interface OneshotOptions {
  model: string;                        // e.g. "gpt-4" or "claude-2" or an alias
  promptFile: string;                   // path to user prompt or direct text
  system?: string;                      // optional single system prompt
  systemFile?: string;                  // or read system prompt from file
  variations?: (string | Variation)[];  // list of variation prompts or objects
  iterations?: number;                  // number of responses per variation
}

export interface ResponseEnvelope {
  variation?: string | Variation;
  systemPrompt: string;
  response: string;
  model: string;
}

export class Oneshot {
  private resolvedModel: string;
  private systemPrompt: string = '';

  constructor(
    private options: OneshotOptions,
    private provider: AIProvider
  ) {
    // Resolve model alias if it exists
    const config = loadConfig();
    this.resolvedModel = config.modelAliases?.[options.model] || options.model;
  }

  async process(): Promise<ResponseEnvelope[]> {
    // Check if prompt file exists
    if (!existsSync(this.options.promptFile)) {
      throw new ToolError(`Oneshot: Prompt file not found: ${this.options.promptFile}`, 'FILE_NOT_FOUND');
    }

    // Check if system file exists
    if (this.options.systemFile && !existsSync(this.options.systemFile)) {
      throw new ToolError(`Oneshot: System file not found: ${this.options.systemFile}`, 'FILE_NOT_FOUND');
    }

    // Initialize system prompt
    this.systemPrompt = '';
    if (this.options.system) {
      this.systemPrompt = this.options.system;
    } else if (this.options.systemFile) {
      try {
        this.systemPrompt = readFileSync(this.options.systemFile, 'utf-8');
      } catch (error: any) {
        throw new ToolError(`Oneshot: Failed to read system file: ${error.message}`, 'FILE_READ_ERROR');
      }
    }

    // Get prompt content from file
    let promptContent: string;
    try {
      promptContent = readFileSync(this.options.promptFile, 'utf-8');
    } catch (error: any) {
      throw new ToolError(`Oneshot: Failed to read prompt: ${error.message}`, 'FILE_READ_ERROR');
    }

    // Process variations
    const variations = this.options.variations || [undefined];
    const iterations = this.options.iterations || 1;

    // Run all variations and iterations
    const responses: ResponseEnvelope[] = [];
    for (const variation of variations) {
      for (let i = 0; i < iterations; i++) {
        // Handle variation object or string
        let variationPrompt = '';
        let variationSystem = this.systemPrompt;
        let variationModel = this.resolvedModel;

        if (typeof variation === 'string') {
          variationPrompt = variation;
        } else if (variation) {
          variationPrompt = variation.prompt || '';
          variationSystem = variation.system || this.systemPrompt;
          if (variation.model) {
            const config = loadConfig();
            variationModel = config.modelAliases?.[variation.model] || variation.model;
          }
        }

        const combinedPrompt = variationPrompt ? `${promptContent}\n\n${variationPrompt}` : promptContent;
        const response = await this.provider.sendPrompt({
          model: variationModel,
          systemPrompt: variationSystem,
          userPrompt: combinedPrompt
        });

        responses.push({
          variation,
          systemPrompt: variationSystem,
          response,
          model: variationModel
        });
      }
    }

    return responses;
  }
} 