import { ElicitationQuestion, ElicitationFlow, ElicitationContext, ElicitationResult } from '../types/elicitation.js';

export class ElicitationManager {
  private flows: Map<string, ElicitationFlow> = new Map();
  
  registerFlow(flow: ElicitationFlow): void {
    this.flows.set(flow.id, flow);
  }

  getFlow(id: string): ElicitationFlow | undefined {
    return this.flows.get(id);
  }

  async runFlow(
    flowId: string, 
    context: ElicitationContext,
    askQuestion: (question: ElicitationQuestion) => Promise<any>
  ): Promise<ElicitationResult> {
    const flow = this.flows.get(flowId);
    if (!flow) {
      throw new Error(`Elicitation flow '${flowId}' not found`);
    }

    const answers: Record<string, any> = {};
    const skipped: string[] = [];

    for (const question of flow.questions) {
      // Check condition
      if (question.condition && !question.condition(context)) {
        skipped.push(question.id);
        continue;
      }

      try {
        const answer = await askQuestion(question);
        
        // Validate answer
        if (question.validation) {
          const validationResult = question.validation(answer);
          if (validationResult !== true) {
            throw new Error(
              typeof validationResult === 'string' 
                ? validationResult 
                : `Invalid answer for ${question.id}`
            );
          }
        }

        answers[question.id] = answer;
        // Update context with answer
        context[question.id] = answer;
      } catch (error) {
        if (question.required) {
          throw error;
        }
        skipped.push(question.id);
      }
    }

    const result: ElicitationResult = {
      answers,
      skipped,
      context,
    };

    if (flow.onComplete) {
      flow.onComplete(answers);
    }

    return result;
  }

  // Pre-defined flows
  static createProjectSetupFlow(): ElicitationFlow {
    return {
      id: 'project_setup',
      title: 'Project Setup',
      description: 'Configure your new project',
      questions: [
        {
          id: 'projectType',
          prompt: 'What type of project are you building?',
          type: 'choice',
          options: ['saas', 'marketplace', 'ai-tool', 'mobile-app', 'cli-tool', 'library', 'other'],
          required: true,
          helpText: 'This helps us provide better templates and suggestions',
        },
        {
          id: 'language',
          prompt: 'Primary programming language?',
          type: 'choice',
          options: ['typescript', 'javascript', 'python', 'rust', 'go', 'other'],
          default: 'typescript',
          required: true,
        },
        {
          id: 'testFramework',
          prompt: 'Which test framework would you like to use?',
          type: 'choice',
          options: ['jest', 'vitest', 'mocha', 'pytest', 'cargo-test', 'go-test', 'none'],
          condition: (ctx) => ['typescript', 'javascript', 'python', 'rust', 'go'].includes(ctx.language),
          default: 'jest',
        },
        {
          id: 'tddMode',
          prompt: 'How strictly should we enforce Test-Driven Development?',
          type: 'choice',
          options: ['strict', 'advisory', 'off'],
          default: 'strict',
          helpText: 'Strict: Must write tests first. Advisory: Suggestions only. Off: No TDD enforcement.',
        },
        {
          id: 'coverageTarget',
          prompt: 'Target test coverage percentage?',
          type: 'number',
          default: 80,
          validation: (value) => {
            if (value < 0 || value > 100) {
              return 'Coverage must be between 0 and 100';
            }
            return true;
          },
          condition: (ctx) => ctx.testFramework !== 'none',
        },
      ],
    };
  }

  static createFeatureFlow(): ElicitationFlow {
    return {
      id: 'new_feature',
      title: 'New Feature Planning',
      description: 'Plan your feature with TDD in mind',
      questions: [
        {
          id: 'featureType',
          prompt: 'What type of feature are you building?',
          type: 'choice',
          options: ['api-endpoint', 'ui-component', 'data-model', 'integration', 'utility', 'other'],
          required: true,
        },
        {
          id: 'complexity',
          prompt: 'Estimated complexity?',
          type: 'choice',
          options: ['simple', 'moderate', 'complex'],
          default: 'moderate',
          helpText: 'This helps determine the number of tests needed',
        },
        {
          id: 'testStrategy',
          prompt: 'Testing strategy?',
          type: 'multi-choice',
          options: ['unit', 'integration', 'e2e', 'performance', 'security'],
          default: ['unit'],
          condition: (ctx) => ctx.complexity !== 'simple',
        },
        {
          id: 'dependencies',
          prompt: 'Will this feature have external dependencies?',
          type: 'boolean',
          default: false,
        },
        {
          id: 'breakingChanges',
          prompt: 'Will this introduce breaking changes?',
          type: 'boolean',
          default: false,
          helpText: 'Breaking changes require additional tests and documentation',
        },
      ],
    };
  }
}