#!/usr/bin/env node
/**
 * Response Generator with Self-Correcting Memory
 * 
 * Architecture:
 * 1. Load context (rules + prefs + memory)
 * 2. Generate draft
 * 3. Critic validates
 * 4. If violations → regenerate with corrections
 * 5. If new patterns → auto-store as corrections
 * 6. Return validated response
 */

const ContextPipeline = require('./pipeline');
const CriticEngine = require('./critic');
const MemoryService = require('./memory-service');

class ResponseGenerator {
  constructor(config = {}) {
    this.pipeline = new ContextPipeline();
    this.critic = new CriticEngine({
      strictMode: config.strictMode || false,
      autoLearn: config.autoLearn !== false
    });
    this.memory = config.memoryService || null;
    this.workflow = config.workflow || 'default';
    this.maxRetries = config.maxRetries || 3;
  }

  /**
   * Generate validated response
   */
  async generate(taskInput, options = {}) {
    const startTime = Date.now();
    
    // Step 1: Load context
    await this.pipeline
      .loadRules()
      .then(() => this.pipeline.loadPreferences())
      .then(() => this.pipeline.loadRelevantMemory(taskInput));
    
    const contextPacket = this.pipeline.buildPacket(taskInput);
    
    // Step 2-4: Generate with validation loop
    let attempts = 0;
    let lastViolations = [];
    let response = null;
    let criticResult = null;
    
    while (attempts < this.maxRetries) {
      attempts++;
      
      // Generate draft (in real implementation, this calls LLM)
      response = await this.callLLM(contextPacket, lastViolations);
      
      // Validate
      criticResult = await this.critic.critique(response, {
        task: taskInput,
        workflow: this.workflow,
        attempt: attempts
      });
      
      if (criticResult.passed) {
        break; // Success!
      }
      
      // Blocked - need to regenerate
      lastViolations = criticResult.violations;
      console.log(`[GENERATOR] Attempt ${attempts} blocked: ${criticResult.violations.map(v => v.message).join(', ')}`);
    }
    
    const processingTime = Date.now() - startTime;
    
    // Step 5: Log validation run
    if (this.memory) {
      await this.memory.logValidation({
        id: `run_${Date.now()}`,
        sessionId: options.sessionId || 'unknown',
        inputLength: taskInput.length,
        outputLength: response.length,
        violationsFound: criticResult.violations.length,
        newPatternsDetected: criticResult.newPatterns.length,
        correctionsAutoStored: criticResult.violations.filter(v => v.autoStored).length,
        processingTimeMs: processingTime,
        blocked: attempts > 1,
        workflow: this.workflow
      });
    }
    
    return {
      response: criticResult.corrected,
      original: criticResult.original,
      attempts,
      passed: criticResult.passed,
      violations: criticResult.violations,
      newPatterns: criticResult.newPatterns,
      processingTimeMs: processingTime,
      context: {
        rulesCount: contextPacket.metadata.rules_count,
        prefsCount: contextPacket.metadata.prefs_count,
        memoryCount: contextPacket.metadata.memory_count
      }
    };
  }

  /**
   * Call LLM with context (placeholder - integrate with actual LLM)
   */
  async callLLM(contextPacket, previousViolations = []) {
    // In production, this calls OpenClaw/LLM
    // For now, return a mock response
    
    let prompt = this.buildPrompt(contextPacket, previousViolations);
    
    // Simulate LLM call
    // const response = await llm.generate(prompt);
    
    // For demo: return context to show it works
    return `## Task
${contextPacket.task}

## System Rules
${contextPacket.system.substring(0, 500)}...

## Response
This is 50% faster than before.`; // Intentional violation for testing
  }

  /**
   * Build prompt with corrections injected
   */
  buildPrompt(contextPacket, previousViolations) {
    const parts = [];
    
    // System rules (highest priority)
    parts.push('# SYSTEM RULES\n' + contextPacket.system);
    
    // Corrections from previous attempts
    if (previousViolations.length > 0) {
      parts.push('\n# CORRECTIONS REQUIRED\n');
      for (const violation of previousViolations) {
        parts.push(`- ${violation.message}`);
        if (violation.suggestion) {
          parts.push(`  Fix: ${violation.suggestion}`);
        }
      }
    }
    
    // Preferences
    if (contextPacket.preferences) {
      parts.push('\n# USER PREFERENCES\n' + contextPacket.preferences);
    }
    
    // Memory
    if (contextPacket.memory) {
      parts.push('\n# RELEVANT MEMORY\n' + contextPacket.memory);
    }
    
    // Task
    parts.push('\n# TASK\n' + contextPacket.task);
    parts.push('\nRespond following all system rules and corrections above.');
    
    return parts.join('\n');
  }

  /**
   * Manual correction entry (user feedback)
   */
  async addUserCorrection(originalText, correctionText, reason) {
    const correction = await this.critic.addManualCorrection(
      originalText,
      correctionText,
      reason
    );
    
    if (this.memory) {
      await this.memory.storeCorrection(correction);
    }
    
    return correction;
  }
}

// Export
module.exports = ResponseGenerator;

// CLI usage
if (require.main === module) {
  const generator = new ResponseGenerator({
    workflow: process.argv[2] || 'coding',
    strictMode: true,
    autoLearn: true
  });
  
  const task = process.argv[3] || 'Write a function to process data';
  
  generator.generate(task)
    .then(result => {
      console.log('=== GENERATION RESULT ===');
      console.log(JSON.stringify(result, null, 2));
    })
    .catch(err => {
      console.error('Generation failed:', err);
      process.exit(1);
    });
}
