// src/services/ai/pipelineOrchestrator.ts
import { getCompressedToolsDataForAI } from '../../utils/dataService.js';
import { getPrompt } from '../../config/prompts.js';
import { config } from '../../config/appConfig.js';
import { aiService } from './aiService.js';
import { toolSelector } from './toolSelector.js';
import { confidenceService } from './confidenceService.js';
import { auditService } from '../../utils/auditService.js';
import { logger } from '../logger.js';

export interface AnalysisResult {
  recommendation: any;
  processingStats: {
    embeddingsUsed: boolean;
    candidatesFromEmbeddings: number;
    finalSelectedItems: number;
    processingTimeMs: number;
    microTasksCompleted: number;
    microTasksFailed: number;
    contextContinuityUsed: boolean;
  };
}

export interface AnalysisContext {
  userQuery: string;
  mode: string;
  filteredData: any;
  selectedTools?: Array<{
    tool: any;
    phase: string;
    priority: string;
    justification?: string;
    taskRelevance?: number;
    limitations?: string[];
  }>;
  backgroundKnowledge?: Array<{
    concept: any;
    relevance: string;
  }>;
  seenToolNames: Set<string>;
  embeddingsSimilarities: Map<string, number>;
  scenarioAnalysis?: string;
  problemAnalysis?: string;
  investigationApproach?: string;
  criticalConsiderations?: string;
}

export class PipelineOrchestrator {
  private readonly microTaskDelay: number;

  constructor() {
    this.microTaskDelay = config.ai.microTaskDelay;
    logger.info('pipeline', 'Pipeline orchestrator initialized');
  }

  async processQuery(userQuery: string, mode: string): Promise<AnalysisResult> {
    const startTime = Date.now();
    let completeTasks = 0;
    let failedTasks = 0;
    
    logger.pipeline('initialization', 'processing started', { userQuery: userQuery.slice(0, 50), mode });

    try {
      const toolsData = await getCompressedToolsDataForAI();
      
      const context: AnalysisContext = {
        userQuery,
        mode,
        filteredData: {},
        seenToolNames: new Set<string>(),
        embeddingsSimilarities: new Map<string, number>()
      };

      // Step 1: Get candidates and select tools
      const candidateData = await toolSelector.getCandidates(userQuery, toolsData);
      const toolSelection = await toolSelector.selectTools(
        userQuery,
        candidateData.tools,
        candidateData.concepts,
        mode,
        candidateData.selectionMethod
      );
      
      context.filteredData = {
        tools: toolSelection.selectedTools,
        concepts: toolSelection.selectedConcepts,
        domains: toolsData.domains,
        phases: toolsData.phases,
        'domain-agnostic-software': toolsData['domain-agnostic-software']
      };

      // Step 2: Scenario/Problem Analysis
      const analysisResult = await this.analyzeScenario(context);
      if (analysisResult.success) completeTasks++; else failedTasks++;
      await this.delay(this.microTaskDelay);

      // Step 3: Investigation Approach
      const approachResult = await this.generateApproach(context);
      if (approachResult.success) completeTasks++; else failedTasks++;
      await this.delay(this.microTaskDelay);

      // Step 4: Critical Considerations
      const considerationsResult = await this.generateCriticalConsiderations(context);
      if (considerationsResult.success) completeTasks++; else failedTasks++;
      await this.delay(this.microTaskDelay);

      // Step 5: Mode-specific processing
      if (mode === 'workflow') {
        const workflowTasks = await this.processWorkflowMode(context, toolsData);
        completeTasks += workflowTasks.completed;
        failedTasks += workflowTasks.failed;
      } else {
        const toolTasks = await this.processToolMode(context);
        completeTasks += toolTasks.completed;
        failedTasks += toolTasks.failed;
      }

      // Step 6: Background Knowledge
      const knowledgeResult = await this.selectBackgroundKnowledge(context);
      if (knowledgeResult.success) completeTasks++; else failedTasks++;
      await this.delay(this.microTaskDelay);

      // Step 7: Final Recommendations
      const finalResult = await this.generateFinalRecommendations(context);
      if (finalResult.success) completeTasks++; else failedTasks++;

      const recommendation = this.buildRecommendation(context, mode, finalResult.content);

      const processingStats = {
        embeddingsUsed: candidateData.selectionMethod === 'embeddings_candidates',
        candidatesFromEmbeddings: candidateData.tools.length,
        finalSelectedItems: (context.selectedTools?.length || 0) + (context.backgroundKnowledge?.length || 0),
        processingTimeMs: Date.now() - startTime,
        microTasksCompleted: completeTasks,
        microTasksFailed: failedTasks,
        contextContinuityUsed: true
      };

      logger.pipeline('completion', 'processing completed', {
        duration: `${processingStats.processingTimeMs}ms`,
        tasksCompleted: completeTasks,
        tasksFailed: failedTasks,
        finalItems: processingStats.finalSelectedItems
      });

      return {
        recommendation: {
          ...recommendation,
          auditTrail: auditService.isEnabled() ? [] : undefined // Audit trail handled by auditService
        },
        processingStats
      };

    } catch (error) {
      const duration = Date.now() - startTime;
      logger.error('pipeline', 'Processing failed', error as Error, {
        duration: `${duration}ms`,
        completedTasks: completeTasks,
        failedTasks: failedTasks
      });
      throw error;
    }
  }

  private async analyzeScenario(context: AnalysisContext): Promise<{ success: boolean; content: string }> {
    try {
      const isWorkflow = context.mode === 'workflow';
      const prompt = getPrompt('scenarioAnalysis', isWorkflow, context.userQuery);
      
      const response = await aiService.callMicroTask(prompt, 'scenario-analysis', 400);
      
      if (isWorkflow) {
        context.scenarioAnalysis = response.content;
      } else {
        context.problemAnalysis = response.content;
      }
      
      logger.pipeline('micro-task', `${isWorkflow ? 'scenario' : 'problem'} analysis completed`);
      return { success: true, content: response.content };
      
    } catch (error) {
      logger.error('pipeline', 'Scenario analysis failed', error as Error);
      return { success: false, content: '' };
    }
  }

  private async generateApproach(context: AnalysisContext): Promise<{ success: boolean; content: string }> {
    try {
      const isWorkflow = context.mode === 'workflow';
      const prompt = getPrompt('investigationApproach', isWorkflow, context.userQuery);
      
      const response = await aiService.callMicroTask(prompt, 'investigation-approach', 400);
      context.investigationApproach = response.content;
      
      logger.pipeline('micro-task', 'investigation approach completed');
      return { success: true, content: response.content };
      
    } catch (error) {
      logger.error('pipeline', 'Investigation approach failed', error as Error);
      return { success: false, content: '' };
    }
  }

  private async generateCriticalConsiderations(context: AnalysisContext): Promise<{ success: boolean; content: string }> {
    try {
      const isWorkflow = context.mode === 'workflow';
      const prompt = getPrompt('criticalConsiderations', isWorkflow, context.userQuery);
      
      const response = await aiService.callMicroTask(prompt, 'critical-considerations', 350);
      context.criticalConsiderations = response.content;
      
      logger.pipeline('micro-task', 'critical considerations completed');
      return { success: true, content: response.content };
      
    } catch (error) {
      logger.error('pipeline', 'Critical considerations failed', error as Error);
      return { success: false, content: '' };
    }
  }

  private async processWorkflowMode(context: AnalysisContext, toolsData: any): Promise<{ completed: number; failed: number }> {
    let completed = 0;
    let failed = 0;
    
    const phases = toolsData.phases || [];
    
    for (const phase of phases) {
      try {
        const result = await this.selectToolsForPhase(context, phase);
        if (result.success) completed++; else failed++;
        await this.delay(this.microTaskDelay);
      } catch (error) {
        logger.error('pipeline', `Phase ${phase.id} tool selection failed`, error as Error);
        failed++;
      }
    }
    
    logger.pipeline('workflow', 'phase processing completed', {
      phases: phases.length,
      completed,
      failed
    });
    
    return { completed, failed };
  }

  private async processToolMode(context: AnalysisContext): Promise<{ completed: number; failed: number }> {
    let completed = 0;
    let failed = 0;
    
    const topTools = context.filteredData.tools.slice(0, 3);
    
    for (let i = 0; i < topTools.length; i++) {
      try {
        const result = await this.evaluateSpecificTool(context, topTools[i], i + 1);
        if (result.success) completed++; else failed++;
        await this.delay(this.microTaskDelay);
      } catch (error) {
        logger.error('pipeline', `Tool evaluation failed for ${topTools[i]?.name}`, error as Error);
        failed++;
      }
    }
    
    logger.pipeline('tool-mode', 'tool evaluation completed', {
      toolsEvaluated: topTools.length,
      completed,
      failed
    });
    
    return { completed, failed };
  }

  private async selectToolsForPhase(context: AnalysisContext, phase: any): Promise<{ success: boolean }> {
    const phaseTools = context.filteredData.tools.filter((tool: any) =>
      tool && tool.phases && Array.isArray(tool.phases) && tool.phases.includes(phase.id)
    );

    if (phaseTools.length === 0) {
      logger.debug('pipeline', `No tools available for phase ${phase.id}`);
      return { success: true };
    }

    try {
      const prompt = getPrompt('phaseToolSelection', context.userQuery, phase, phaseTools);
      const response = await aiService.callMicroTask(prompt, `phase-${phase.id}`, 1000);
      
      const selections = aiService.parseJSONResponse(response.content, []);
      
      if (Array.isArray(selections)) {
        const validSelections = selections.filter((sel: any) => {
          return phaseTools.some((tool: any) => tool && tool.name === sel.toolName);
        });
        
        validSelections.forEach((sel: any) => {
          const tool = phaseTools.find((t: any) => t && t.name === sel.toolName);
          if (tool) {
            const taskRelevance = typeof sel.taskRelevance === 'number' ?
              sel.taskRelevance : parseInt(String(sel.taskRelevance)) || 70;
            
            this.addToolToSelection(context, tool, phase.id, this.derivePriorityFromScore(taskRelevance), 
              sel.justification, taskRelevance, sel.limitations);
          }
        });
        
        logger.pipeline('phase-selection', `Phase ${phase.id} completed`, {
          available: phaseTools.length,
          selected: validSelections.length
        });
      }
      
      return { success: true };
      
    } catch (error) {
      logger.error('pipeline', `Phase ${phase.id} tool selection failed`, error as Error);
      return { success: false };
    }
  }

  private async evaluateSpecificTool(context: AnalysisContext, tool: any, rank: number): Promise<{ success: boolean }> {
    try {
      const existingSelection = context.selectedTools?.find((st: any) => st.tool && st.tool.name === tool.name);
      const taskRelevance = existingSelection?.taskRelevance || 70;
      const priority = this.derivePriorityFromScore(taskRelevance);
      
      const prompt = getPrompt('toolEvaluation', context.userQuery, tool, rank, taskRelevance);
      const response = await aiService.callMicroTask(prompt, `tool-eval-${tool.name}`, 1000);
      
      const evaluation = aiService.parseJSONResponse(response.content, {
        detailed_explanation: 'Evaluation failed',
        implementation_approach: '',
        pros: [],
        limitations: [],
        alternatives: ''
      });
      
      this.addToolToSelection(context, {
        ...tool,
        evaluation: {
          ...evaluation,
          rank,
          task_relevance: taskRelevance
        }
      }, 'evaluation', priority, evaluation.detailed_explanation, taskRelevance, evaluation.limitations);
      
      logger.pipeline('tool-evaluation', `Tool ${tool.name} evaluated`, { rank, taskRelevance });
      return { success: true };
      
    } catch (error) {
      logger.error('pipeline', `Tool evaluation failed for ${tool.name}`, error as Error);
      return { success: false };
    }
  }

  private async selectBackgroundKnowledge(context: AnalysisContext): Promise<{ success: boolean }> {
    const availableConcepts = context.filteredData.concepts;
    
    if (availableConcepts.length === 0) {
      return { success: true };
    }

    try {
      const selectedToolNames = context.selectedTools?.map((st: any) => st.tool && st.tool.name).filter(Boolean) || [];
      const prompt = getPrompt('backgroundKnowledgeSelection', context.userQuery, context.mode, selectedToolNames, availableConcepts);
      const response = await aiService.callMicroTask(prompt, 'background-knowledge', 700);
      
      const selections = aiService.parseJSONResponse(response.content, []);
      
      if (Array.isArray(selections)) {
        context.backgroundKnowledge = selections.filter((sel: any) =>
          sel.conceptName && availableConcepts.some((concept: any) => concept.name === sel.conceptName)
        ).map((sel: any) => ({
          concept: availableConcepts.find((c: any) => c.name === sel.conceptName),
          relevance: sel.relevance
        }));
        
        logger.pipeline('background-knowledge', 'selection completed', {
          available: availableConcepts.length,
          selected: context.backgroundKnowledge?.length || 0
        });
      }
      
      return { success: true };
      
    } catch (error) {
      logger.error('pipeline', 'Background knowledge selection failed', error as Error);
      return { success: false };
    }
  }

  private async generateFinalRecommendations(context: AnalysisContext): Promise<{ success: boolean; content: string }> {
    try {
      const selectedToolNames = context.selectedTools?.map((st: any) => st.tool && st.tool.name).filter(Boolean) || [];
      const prompt = getPrompt('finalRecommendations', context.mode === 'workflow', context.userQuery, selectedToolNames);
      
      const response = await aiService.callMicroTask(prompt, 'final-recommendations', 350);
      
      logger.pipeline('final', 'recommendations generated');
      return { success: true, content: response.content };
      
    } catch (error) {
      logger.error('pipeline', 'Final recommendations failed', error as Error);
      return { success: false, content: '' };
    }
  }

  private addToolToSelection(
    context: AnalysisContext,
    tool: any,
    phase: string,
    priority: string,
    justification?: string,
    taskRelevance?: number,
    limitations?: string[]
  ): void {
    context.seenToolNames.add(tool.name);
    if (!context.selectedTools) context.selectedTools = [];
    
    context.selectedTools.push({
      tool,
      phase,
      priority,
      justification,
      taskRelevance,
      limitations
    });
  }

  private derivePriorityFromScore(taskRelevance: number): string {
    if (taskRelevance >= 80) return 'high';
    if (taskRelevance >= 60) return 'medium';
    return 'low';
  }

  private async delay(ms: number): Promise<void> {
    return new Promise(resolve => setTimeout(resolve, ms));
  }

  private buildRecommendation(context: AnalysisContext, mode: string, finalContent: string): any {
    const isWorkflow = mode === 'workflow';
    
    const base = {
      [isWorkflow ? 'scenario_analysis' : 'problem_analysis']: 
        isWorkflow ? context.scenarioAnalysis : context.problemAnalysis,
      investigation_approach: context.investigationApproach,
      critical_considerations: context.criticalConsiderations,
      background_knowledge: context.backgroundKnowledge?.map((bk: any) => ({
        concept_name: bk.concept.name,
        relevance: bk.relevance
      })) || []
    };

    if (isWorkflow) {
      const recommendedToolsWithConfidence = context.selectedTools?.map((st: any) => {
        const confidence = confidenceService.calculateRecommendationConfidence(
          st.tool,
          context,
          st.taskRelevance || 70,
          st.limitations || []
        );

        return {
          name: st.tool.name,
          type: st.tool.type,
          phase: st.phase,
          priority: st.priority,
          justification: st.justification || `Empfohlen für ${st.phase}`,
          confidence,
          recommendationStrength: confidenceService.getConfidenceLevel(confidence.overall)
        };
      }) || [];

      return {
        ...base,
        recommended_tools: recommendedToolsWithConfidence,
        workflow_suggestion: finalContent
      };
    } else {
      const recommendedToolsWithConfidence = context.selectedTools?.map((st: any) => {
        const confidence = confidenceService.calculateRecommendationConfidence(
          st.tool,
          context,
          st.taskRelevance || 70,
          st.limitations || []
        );

        return {
          name: st.tool.name,
          type: st.tool.type,
          rank: st.tool.evaluation?.rank || 1,
          suitability_score: st.priority,
          detailed_explanation: st.tool.evaluation?.detailed_explanation || '',
          implementation_approach: st.tool.evaluation?.implementation_approach || '',
          pros: st.tool.evaluation?.pros || [],
          cons: st.tool.evaluation?.limitations || [],
          alternatives: st.tool.evaluation?.alternatives || '',
          confidence,
          recommendationStrength: confidenceService.getConfidenceLevel(confidence.overall)
        };
      }) || [];

      return {
        ...base,
        recommended_tools: recommendedToolsWithConfidence,
        additional_considerations: finalContent
      };
    }
  }
}

export const pipelineOrchestrator = new PipelineOrchestrator();