/**
 * LLM Analyzer Service
 * Integrates with LLM services for advanced work pattern analysis and insight generation
 */

import { 
  LLMAnalysisRequest, 
  LLMAnalysisResponse, 
  AnalyticsInsight
} from '@/lib/types/analytics';
import { TimeEntry } from '@/lib/types/database';

export class LLMAnalyzer {
  private apiKey: string;
  private baseUrl: string;
  private model: string;
  private cache: Map<string, { data: LLMAnalysisResponse; timestamp: number }>;
  private cacheTimeout: number = 30 * 60 * 1000; // 30 minutes

  constructor() {
    this.apiKey = process.env.OPENAI_API_KEY || process.env.ANTHROPIC_API_KEY || '';
    this.baseUrl = process.env.OPENAI_BASE_URL || 'https://api.openai.com/v1';
    this.model = process.env.LLM_MODEL || 'gpt-3.5-turbo';
    this.cache = new Map();
  }

  /**
   * Analyze time entries using LLM for work patterns and insights
   */
  async analyzeTimeEntries(request: LLMAnalysisRequest): Promise<LLMAnalysisResponse> {
    // Check cache first
    const cacheKey = this.generateCacheKey(request);
    const cached = this.cache.get(cacheKey);
    
    if (cached && Date.now() - cached.timestamp < this.cacheTimeout) {
      console.log('LLM Analyzer: Returning cached result');
      return cached.data;
    }

    const startTime = Date.now();
    
    try {
      const response = await this.callLLM(request);
      const processingTime = Date.now() - startTime;
      
      // Cache the result
      this.cache.set(cacheKey, {
        data: response,
        timestamp: Date.now(),
      });

      // Add processing metadata
      response.processingTime = processingTime;
      
      console.log(`LLM Analyzer: Processed ${request.timeEntries.length} entries in ${processingTime}ms`);
      
      return response;
    } catch (error) {
      console.error('LLM Analyzer: Analysis failed', error);
      throw new Error(`LLM analysis failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
    }
  }

  /**
   * Generate comprehensive insights from time entries
   */
  async generateInsights(timeEntries: TimeEntry[]): Promise<AnalyticsInsight[]> {
    if (timeEntries.length === 0) {
      return [];
    }

    const request: LLMAnalysisRequest = {
      timeEntries: timeEntries.map(entry => ({
        id: entry.id,
        notes: entry.notes || undefined,
        title: entry.title || undefined,
        hours_worked: entry.hours_worked,
        entry_date: entry.entry_date.toISOString(),
        resource_name: entry.resource_id ? `Resource ${entry.resource_id}` : undefined,
        ticket_title: entry.ticket_id ? `Ticket ${entry.ticket_id}` : undefined,
      })),
      analysisType: 'comprehensive',
    };

    const response = await this.analyzeTimeEntries(request);
    
    // Convert LLM insights to AnalyticsInsight format
    const insights: AnalyticsInsight[] = [];
    
    // Add insights from LLM response
    response.insights.forEach((insight, index) => {
      insights.push({
        type: this.determineInsightType(insight),
        category: 'overall',
        title: `AI Insight ${index + 1}`,
        description: insight,
        recommendation: this.extractRecommendation(insight),
        severity: 'medium',
        actionable: true,
      });
    });

    // Add pattern-based insights
    response.patterns.forEach(pattern => {
      insights.push({
        type: pattern.impact === 'high' ? 'warning' : 'info',
        category: 'performance',
        title: `Pattern: ${pattern.type}`,
        description: pattern.description,
        recommendation: `Address this ${pattern.frequency > 5 ? 'frequent' : 'occasional'} pattern`,
        severity: pattern.impact === 'high' ? 'high' : pattern.impact === 'medium' ? 'medium' : 'low',
        actionable: true,
      });
    });

    // Add recommendations
    response.recommendations.forEach(rec => {
      insights.push({
        type: rec.priority === 'high' ? 'warning' : 'info',
        category: 'overall',
        title: `Recommendation: ${rec.category}`,
        description: rec.action,
        recommendation: rec.expectedImpact,
        severity: rec.priority === 'high' ? 'high' : rec.priority === 'medium' ? 'medium' : 'low',
        actionable: true,
      });
    });

    return insights;
  }

  /**
   * Analyze productivity patterns
   */
  async analyzeProductivity(timeEntries: TimeEntry[]): Promise<LLMAnalysisResponse> {
    const request: LLMAnalysisRequest = {
      timeEntries: timeEntries.map(entry => ({
        id: entry.id,
        notes: entry.notes || undefined,
        title: entry.title || undefined,
        hours_worked: entry.hours_worked,
        entry_date: entry.entry_date.toISOString(),
        resource_name: entry.resource_id ? `Resource ${entry.resource_id}` : undefined,
      })),
      analysisType: 'productivity',
    };

    return this.analyzeTimeEntries(request);
  }

  /**
   * Analyze work quality patterns
   */
  async analyzeQuality(timeEntries: TimeEntry[]): Promise<LLMAnalysisResponse> {
    const request: LLMAnalysisRequest = {
      timeEntries: timeEntries.map(entry => ({
        id: entry.id,
        notes: entry.notes || undefined,
        title: entry.title || undefined,
        hours_worked: entry.hours_worked,
        entry_date: entry.entry_date.toISOString(),
        ticket_title: entry.ticket_id ? `Ticket ${entry.ticket_id}` : undefined,
      })),
      analysisType: 'quality',
    };

    return this.analyzeTimeEntries(request);
  }

  /**
   * Detect anomalies in time entry patterns
   */
  async detectAnomalies(timeEntries: TimeEntry[]): Promise<LLMAnalysisResponse> {
    const request: LLMAnalysisRequest = {
      timeEntries: timeEntries.map(entry => ({
        id: entry.id,
        notes: entry.notes || undefined,
        title: entry.title || undefined,
        hours_worked: entry.hours_worked,
        entry_date: entry.entry_date.toISOString(),
        resource_name: entry.resource_id ? `Resource ${entry.resource_id}` : undefined,
      })),
      analysisType: 'anomalies',
    };

    return this.analyzeTimeEntries(request);
  }

  /**
   * Call the LLM API
   */
  private async callLLM(request: LLMAnalysisRequest): Promise<LLMAnalysisResponse> {
    const prompt = this.buildPrompt(request);
    
    const payload = {
      model: this.model,
      messages: [
        {
          role: 'system',
          content: this.getSystemPrompt(request.analysisType),
        },
        {
          role: 'user',
          content: prompt,
        },
      ],
      temperature: 0.3,
      max_tokens: 1500,
    };

    const response = await fetch(`${this.baseUrl}/chat/completions`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${this.apiKey}`,
      },
      body: JSON.stringify(payload),
    });

    if (!response.ok) {
      const errorText = await response.text();
      throw new Error(`LLM API error: ${response.status} - ${errorText}`);
    }

    const data = await response.json();
    const content = data.choices[0]?.message?.content;
    
    if (!content) {
      throw new Error('No content received from LLM');
    }

    return this.parseResponse(content, data.usage?.total_tokens || 0);
  }

  /**
   * Build the prompt for LLM analysis
   */
  private buildPrompt(request: LLMAnalysisRequest): string {
    const timeEntriesText = request.timeEntries.map(entry => 
      `ID: ${entry.id}, Date: ${entry.entry_date}, Hours: ${entry.hours_worked}, Title: "${entry.title || 'No title'}", Notes: "${entry.notes || 'No notes'}", Resource: ${entry.resource_name || 'Unknown'}`
    ).join('\n');

    let prompt = `Analyze the following time entries:\n\n${timeEntriesText}\n\n`;

    switch (request.analysisType) {
      case 'productivity':
        prompt += `Focus on productivity patterns, work efficiency, time utilization, and identify any productivity bottlenecks or high-performing patterns.`;
        break;
      case 'quality':
        prompt += `Focus on work quality, documentation detail, technical accuracy, and identify areas where documentation quality could be improved.`;
        break;
      case 'patterns':
        prompt += `Focus on recurring work patterns, routine tasks, common issues, and identify any patterns that could be optimized or automated.`;
        break;
      case 'anomalies':
        prompt += `Focus on unusual patterns, outliers, suspicious entries, and identify any anomalies that may require investigation.`;
        break;
      case 'comprehensive':
      default:
        prompt += `Provide a comprehensive analysis covering productivity, quality, patterns, and any notable insights or recommendations.`;
        break;
    }

    if (request.context) {
      prompt += `\n\nContext: Time range ${request.context.timeRange}`;
      if (request.context.resourceIds) {
        prompt += `, Resources: ${request.context.resourceIds.join(', ')}`;
      }
      if (request.context.projectIds) {
        prompt += `, Projects: ${request.context.projectIds.join(', ')}`;
      }
    }

    prompt += `\n\nPlease provide your analysis in the following JSON format:
{
  "insights": ["insight 1", "insight 2", "insight 3"],
  "patterns": [
    {"type": "pattern name", "description": "description", "frequency": number, "impact": "low|medium|high"}
  ],
  "recommendations": [
    {"category": "category", "priority": "low|medium|high", "action": "action description", "expectedImpact": "impact description"}
  ],
  "summary": {
    "overallQuality": 0.8,
    "productivityLevel": 0.7,
    "keyFindings": ["finding 1", "finding 2"]
  }
}`;

    return prompt;
  }

  /**
   * Get system prompt based on analysis type
   */
  private getSystemPrompt(analysisType: string): string {
    return `You are an expert analyst specializing in time tracking and work pattern analysis. Your task is to analyze time entries and provide actionable insights.

Key considerations:
- Focus on practical, actionable recommendations
- Consider both individual and team patterns
- Highlight both strengths and areas for improvement
- Provide specific, evidence-based insights
- Consider the context of professional services work

Analysis guidelines:
- Be objective and data-driven
- Provide constructive feedback
- Suggest realistic improvements
- Consider industry best practices for time tracking
- Account for variations in work types and complexity

Respond with valid JSON only, no additional text.`;
  }

  /**
   * Parse LLM response into structured format
   */
  private parseResponse(content: string, tokensUsed: number): LLMAnalysisResponse {
    try {
      // Extract JSON from response
      const jsonMatch = content.match(/\{[\s\S]*\}/);
      if (!jsonMatch) {
        throw new Error('No JSON found in LLM response');
      }

      const parsed = JSON.parse(jsonMatch[0]);
      
      // Validate and set defaults
      return {
        insights: Array.isArray(parsed.insights) ? parsed.insights : [],
        patterns: Array.isArray(parsed.patterns) ? parsed.patterns : [],
        recommendations: Array.isArray(parsed.recommendations) ? parsed.recommendations : [],
        summary: {
          overallQuality: parsed.summary?.overallQuality || 0.5,
          productivityLevel: parsed.summary?.productivityLevel || 0.5,
          keyFindings: Array.isArray(parsed.summary?.keyFindings) ? parsed.summary.keyFindings : [],
        },
        processingTime: 0, // Will be set by caller
        tokensUsed,
      };
    } catch (error) {
      console.error('Failed to parse LLM response:', error);
      console.error('Response content:', content);
      
      // Return fallback response
      return {
        insights: ['Unable to process AI analysis due to parsing error'],
        patterns: [],
        recommendations: [],
        summary: {
          overallQuality: 0.5,
          productivityLevel: 0.5,
          keyFindings: ['Analysis processing failed'],
        },
        processingTime: 0,
        tokensUsed,
      };
    }
  }

  /**
   * Determine insight type from content
   */
  private determineInsightType(insight: string): 'success' | 'warning' | 'error' | 'info' {
    const lowerInsight = insight.toLowerCase();
    
    if (lowerInsight.includes('excellent') || lowerInsight.includes('great') || lowerInsight.includes('good')) {
      return 'success';
    }
    if (lowerInsight.includes('concern') || lowerInsight.includes('issue') || lowerInsight.includes('problem')) {
      return 'warning';
    }
    if (lowerInsight.includes('error') || lowerInsight.includes('failed') || lowerInsight.includes('critical')) {
      return 'error';
    }
    
    return 'info';
  }

  /**
   * Extract recommendation from insight
   */
  private extractRecommendation(insight: string): string {
    // Simple extraction - in a real implementation, this could be more sophisticated
    if (insight.includes('recommend') || insight.includes('should') || insight.includes('consider')) {
      return insight;
    }
    
    return 'Review this insight and consider appropriate action';
  }

  /**
   * Generate cache key for request
   */
  private generateCacheKey(request: LLMAnalysisRequest): string {
    const keyData = {
      analysisType: request.analysisType,
      entryCount: request.timeEntries.length,
      dateRange: {
        start: request.timeEntries[0]?.entry_date,
        end: request.timeEntries[request.timeEntries.length - 1]?.entry_date,
      },
      context: request.context,
    };
    
    return Buffer.from(JSON.stringify(keyData)).toString('base64');
  }

  /**
   * Clear cache
   */
  clearCache(): void {
    this.cache.clear();
  }

  /**
   * Get cache statistics
   */
  getCacheStats(): { size: number; hitRate: number } {
    return {
      size: this.cache.size,
      hitRate: 0, // Would need to track hits/misses for real implementation
    };
  }
}

// Create singleton instance
export const llmAnalyzer = new LLMAnalyzer();
