// Orchestrator Agent - Coordinates all agents

const axios = require('axios');
const ContextManager = require('./contextManager');
const ReasonerAgent = require('./reasoner');
const NarratorAgent = require('./narrator');
const { ORCHESTRATOR_PROMPT } = require('../prompts/agentPrompts');

const LM_STUDIO_URL = 'http://localhost:1234';

class OrchestratorAgent {
  constructor() {
    this.contextManager = new ContextManager();
    this.reasoner = new ReasonerAgent();
    this.narrator = new NarratorAgent();
    this.maxRevisionIterations = 3;
  }

  // Main entry point - process player input
  async processPlayerInput(sessionId, playerInput) {
    console.log(`\n[ORCHESTRATOR] Processing input for session ${sessionId}`);
    console.log(`[ORCHESTRATOR] Player: "${playerInput}"`);

    try {
      // Step 1: Get full context
      console.log('[ORCHESTRATOR] Step 1: Gathering context...');
      const context = await this.contextManager.getFullContext(sessionId);
      console.log(`[ORCHESTRATOR] Context loaded: ${context.characters.length} characters, ${context.inventory.length} items`);

      // Step 2: Get constraints from Reasoner
      console.log('[ORCHESTRATOR] Step 2: Getting constraints from Reasoner...');
      let guidance;
      try {
        guidance = await this.reasoner.getConstraints(context, playerInput);
      } catch (e) {
        console.warn('[ORCHESTRATOR] Reasoner constraints failed, using defaults');
        guidance = {
          constraints: ['Stay in present moment', 'No player action assumptions', 'Reference established context'],
          expectedElements: ['Sensory details', 'Environmental description'],
          warnings: []
        };
      }
      console.log(`[ORCHESTRATOR] Constraints: ${guidance.constraints.length}, Warnings: ${guidance.warnings.length}`);

      // Step 3: Generate initial narration
      console.log('[ORCHESTRATOR] Step 3: Generating narration...');
      let narrationResult = await this.narrator.generateNarration(
        context,
        playerInput,
        guidance.constraints,
        guidance.expectedElements
      );

      if (!narrationResult.success) {
        console.error('[ORCHESTRATOR] Narrator failed, using fallback');
        return this.createFallbackResponse(sessionId, playerInput, context);
      }

      let currentNarration = narrationResult.narration;
      let iteration = 0;
      const maxIterations = 2; // Reduced from 3 for speed

      // Step 4: Validate and revise loop
      console.log('[ORCHESTRATOR] Step 4: Validating narration...');
      while (iteration < maxIterations) {
        let validation;
        try {
          validation = await this.reasoner.validateResponse(
            context,
            playerInput,
            currentNarration
          );
        } catch (e) {
          console.warn('[ORCHESTRATOR] Reasoner validation failed, using programmatic check only');
          validation = {
            score: 7,
            approved: true,
            issues: [],
            positiveElements: []
          };
        }

        console.log(`[ORCHESTRATOR] Validation score: ${validation.score}/10, Approved: ${validation.approved}`);

        if (validation.approved) {
          console.log(`[ORCHESTRATOR] Narration approved after ${iteration + 1} iteration(s)`);
          break;
        }

        // Need revision
        iteration++;
        console.log(`[ORCHESTRATOR] Revision needed (iteration ${iteration}/${maxIterations})`);
        console.log(`[ORCHESTRATOR] Issues: ${validation.issues.map(i => i.type).join(', ')}`);

        let revisionGuidance;
        try {
          revisionGuidance = await this.reasoner.getRevisionInstructions(
            context,
            playerInput,
            currentNarration,
            validation.issues
          );
        } catch (e) {
          revisionGuidance = {
            revisionInstructions: validation.issues.map(i => i.fix),
            focusAreas: ['Fix critical issues first']
          };
        }

        narrationResult = await this.narrator.reviseNarration(
          context,
          playerInput,
          currentNarration,
          revisionGuidance.revisionInstructions,
          revisionGuidance.focusAreas
        );

        currentNarration = narrationResult.narration;
      }

      if (iteration >= maxIterations) {
        console.warn('[ORCHESTRATOR] Max revisions reached, using best available');
      }

      // Step 5: Extract context updates
      console.log('[ORCHESTRATOR] Step 5: Extracting context updates...');
      let contextUpdates = {};
      try {
        contextUpdates = await this.narrator.extractContextUpdates(
          context,
          playerInput,
          currentNarration
        );
      } catch (e) {
        console.warn('[ORCHESTRATOR] Context extraction failed, skipping');
      }

      // Step 6: Apply context updates
      console.log('[ORCHESTRATOR] Step 6: Applying context updates...');
      try {
        await this.contextManager.applyContextUpdates(sessionId, {
          ...contextUpdates,
          journal: {
            summaryUpdate: contextUpdates.journal?.summaryUpdate,
            keyEvent: contextUpdates.journal?.keyEvent,
            characterArcNotes: contextUpdates.journal?.characterArcNotes
          }
        });
      } catch (e) {
        console.warn('[ORCHESTRATOR] Context update failed:', e.message);
      }

      // Step 7: Add player and narrator messages to session history
      try {
        const session = this.contextManager.loadSession(sessionId);
        session.messages.push(
          { role: 'user', content: playerInput, timestamp: new Date().toISOString() },
          { role: 'assistant', content: currentNarration, timestamp: new Date().toISOString() }
        );
        this.contextManager.saveSession(sessionId, session);
      } catch (e) {
        console.error('[ORCHESTRATOR] Failed to save messages:', e.message);
      }

      console.log('[ORCHESTRATOR] Complete!');

      return {
        response: currentNarration,
        contextUpdates,
        validationScore: iteration < maxIterations ? 'approved' : 'max-revisions',
        iterations: iteration + 1
      };

    } catch (error) {
      console.error('[ORCHESTRATOR] Error:', error.message);
      console.error('[ORCHESTRATOR] Stack:', error.stack);
      return this.createFallbackResponse(sessionId, playerInput, null, error.message);
    }
  }

  // Fallback response if agents fail
  createFallbackResponse(sessionId, playerInput, context, errorMessage) {
    const fallbackNarration = `*[The world awaits your action...]*

You find yourself in ${context?.currentLocation || 'this place'}. ${context?.characters.length > 0 ? `${context.characters.map(c => c.name).join(', ')} ${context.characters.length === 1 ? 'is' : 'are'} present.` : 'You are alone.'}

What do you do?`;

    // Still save to session
    try {
      const session = this.contextManager.loadSession(sessionId);
      session.messages.push(
        { role: 'user', content: playerInput, timestamp: new Date().toISOString() },
        { role: 'assistant', content: fallbackNarration, timestamp: new Date().toISOString() }
      );
      this.contextManager.saveSession(sessionId, session);
    } catch (e) {
      console.error('[ORCHESTRATOR] Could not save fallback:', e.message);
    }

    return {
      response: fallbackNarration,
      contextUpdates: {},
      validationScore: 'fallback',
      iterations: 0,
      error: errorMessage
    };
  }

  // Get session context (for API endpoint)
  getSessionContext(sessionId) {
    return this.contextManager.getFullContext(sessionId);
  }

  // Clear session context
  clearSessionContext(sessionId, keepMessages = false) {
    const session = this.contextManager.loadSession(sessionId);
    if (!session) throw new Error('Session not found');

    session.context = {
      characters: [],
      locations: [],
      inventory: [],
      quests: [],
      storyState: {},
      currentLocation: null
    };

    session.journal = {
      summary: '',
      keyEvents: [],
      entries: [],
      characterArcs: {},
      locationHistory: []
    };

    if (!keepMessages) {
      session.messages = [];
    }

    this.contextManager.saveSession(sessionId, session);
    return session;
  }
}

module.exports = OrchestratorAgent;
