import { injectable } from 'tsyringe';
import { OpenAIService } from '../../ai/openai.service';
import { TaskClassification, ExtractedEntities } from '../nlp.service';

/**
 * Classification patterns and rules
 */
const TASK_TYPE_PATTERNS = {
  feature: /\b(feature|new functionality|enhancement|add|implement|create new)\b/i,
  bug: /\b(bug|fix|issue|problem|error|broken|not working|crash|defect)\b/i,
  improvement: /\b(improve|optimize|refactor|enhance|better|upgrade|performance)\b/i,
  documentation: /\b(document|docs|readme|guide|tutorial|explain|write docs)\b/i,
  test: /\b(test|testing|unit test|integration test|e2e|coverage|qa)\b/i,
  task: /\b(task|todo|chore|maintenance|update|modify)\b/i,
};

const URGENCY_INDICATORS = {
  immediate: {
    keywords: ['asap', 'immediately', 'urgent', 'emergency', 'critical', 'blocker'],
    sentimentWeight: 2.0,
  },
  urgent: {
    keywords: ['soon', 'quickly', 'high priority', 'important', 'fast'],
    sentimentWeight: 1.5,
  },
  normal: {
    keywords: ['normal', 'standard', 'regular', 'medium'],
    sentimentWeight: 1.0,
  },
  low: {
    keywords: ['low priority', 'when possible', 'nice to have', 'eventually'],
    sentimentWeight: 0.5,
  },
};

const COMPLEXITY_INDICATORS = {
  trivial: {
    keywords: ['simple', 'easy', 'quick', 'minor', 'small'],
    estimateRange: [0, 2], // hours
  },
  simple: {
    keywords: ['straightforward', 'basic', 'standard'],
    estimateRange: [2, 8],
  },
  moderate: {
    keywords: ['moderate', 'medium', 'typical'],
    estimateRange: [8, 24],
  },
  complex: {
    keywords: ['complex', 'difficult', 'challenging', 'large'],
    estimateRange: [24, 80],
  },
  'very-complex': {
    keywords: ['very complex', 'extremely difficult', 'massive', 'epic'],
    estimateRange: [80, Infinity],
  },
};

/**
 * Task Classifier Service for categorizing and analyzing tasks
 */
@injectable()
export class TaskClassifierService {
  constructor(private openAIService: OpenAIService) {}

  /**
   * Classify a task based on text and extracted entities
   */
  async classify(input: {
    text: string;
    entities: ExtractedEntities;
    language: string;
    keywords: string[];
  }): Promise<TaskClassification> {
    const { text, entities, language, keywords } = input;

    // Run all classifications in parallel
    const [
      type,
      urgency,
      sentiment,
      complexity,
    ] = await Promise.all([
      this.classifyType(text, keywords),
      this.detectUrgency(text, entities.priority),
      this.analyzeSentiment(text, language),
      this.assessComplexity(text, entities.estimatedHours),
    ]);

    // Calculate confidence score
    const confidence = this.calculateClassificationConfidence({
      type,
      urgency,
      sentiment,
      complexity,
    });

    return {
      type,
      urgency,
      sentiment,
      complexity,
      confidence,
    };
  }

  /**
   * Classify task type
   */
  private async classifyType(text: string, keywords: string[]): Promise<TaskClassification['type']> {
    // First try pattern matching
    for (const [type, pattern] of Object.entries(TASK_TYPE_PATTERNS)) {
      if (pattern.test(text)) {
        return type as TaskClassification['type'];
      }
    }

    // Check keywords for type hints
    const keywordLower = keywords.map(k => k.toLowerCase());
    if (keywordLower.some(k => ['feature', 'add', 'new'].includes(k))) {
      return 'feature';
    }
    if (keywordLower.some(k => ['bug', 'fix', 'error'].includes(k))) {
      return 'bug';
    }

    // Use AI for more complex classification
    try {
      const prompt = `Classify this task into one of these categories: feature, bug, improvement, documentation, test, task.

Task: "${text}"

Return only the category name, no additional text.`;

      const result = await this.openAIService.complete(
        [{ role: 'user', content: prompt }],
        { maxTokens: 20, temperature: 0.3 }
      );

      const classification = result.content.trim().toLowerCase();
      const validTypes: TaskClassification['type'][] = ['feature', 'bug', 'improvement', 'documentation', 'test', 'task'];
      
      if (validTypes.includes(classification as TaskClassification['type'])) {
        return classification as TaskClassification['type'];
      }
    } catch (error) {
      console.error('AI task type classification failed:', error);
    }

    // Default to generic task
    return 'task';
  }

  /**
   * Detect urgency level from context
   */
  private detectUrgency(text: string, priority?: ExtractedEntities['priority']): TaskClassification['urgency'] {
    const textLower = text.toLowerCase();
    
    // Check for urgency indicators
    for (const [level, config] of Object.entries(URGENCY_INDICATORS)) {
      if (config.keywords.some(keyword => textLower.includes(keyword))) {
        return level as TaskClassification['urgency'];
      }
    }

    // Map priority to urgency
    if (priority) {
      switch (priority) {
        case 'critical':
          return 'immediate';
        case 'high':
          return 'urgent';
        case 'low':
          return 'low';
        default:
          return 'normal';
      }
    }

    // Check for deadline proximity (would need current date context)
    if (text.includes('today') || text.includes('tomorrow')) {
      return 'urgent';
    }

    return 'normal';
  }

  /**
   * Analyze sentiment of the task description
   */
  private async analyzeSentiment(text: string, language: string): Promise<TaskClassification['sentiment']> {
    // Quick sentiment analysis based on keywords
    const positiveWords = ['great', 'excellent', 'good', 'improve', 'enhance', 'better', 'success'];
    const negativeWords = ['problem', 'issue', 'broken', 'fail', 'error', 'bug', 'wrong', 'bad'];
    
    const textLower = text.toLowerCase();
    let positiveCount = 0;
    let negativeCount = 0;

    positiveWords.forEach(word => {
      if (textLower.includes(word)) positiveCount++;
    });

    negativeWords.forEach(word => {
      if (textLower.includes(word)) negativeCount++;
    });

    // Simple heuristic
    if (negativeCount > positiveCount) {
      return 'negative';
    } else if (positiveCount > negativeCount) {
      return 'positive';
    }

    // Use AI for more nuanced sentiment
    try {
      const prompt = `Analyze the sentiment of this ${language} task description. Return only one word: positive, neutral, or negative.

Text: "${text}"`;

      const result = await this.openAIService.complete(
        [{ role: 'user', content: prompt }],
        { maxTokens: 10, temperature: 0.3 }
      );

      const sentiment = result.content.trim().toLowerCase();
      if (['positive', 'neutral', 'negative'].includes(sentiment)) {
        return sentiment as TaskClassification['sentiment'];
      }
    } catch (error) {
      console.error('AI sentiment analysis failed:', error);
    }

    return 'neutral';
  }

  /**
   * Assess task complexity
   */
  private assessComplexity(
    text: string,
    estimatedHours?: number
  ): TaskClassification['complexity'] {
    // First check if we have an estimate
    if (estimatedHours !== undefined) {
      for (const [level, config] of Object.entries(COMPLEXITY_INDICATORS)) {
        const [min, max] = config.estimateRange;
        if (estimatedHours >= min && estimatedHours < max) {
          return level as TaskClassification['complexity'];
        }
      }
    }

    // Check for complexity keywords
    const textLower = text.toLowerCase();
    for (const [level, config] of Object.entries(COMPLEXITY_INDICATORS)) {
      if (config.keywords.some(keyword => textLower.includes(keyword))) {
        return level as TaskClassification['complexity'];
      }
    }

    // Heuristic based on text length and structure
    const wordCount = text.split(/\s+/).length;
    const hasMultipleSentences = text.split(/[.!?]/).length > 2;
    const hasBulletPoints = /[•\-*]\s/.test(text);
    const hasCodeBlocks = /```/.test(text);

    let complexityScore = 0;
    if (wordCount > 100) complexityScore += 2;
    else if (wordCount > 50) complexityScore += 1;
    
    if (hasMultipleSentences) complexityScore += 1;
    if (hasBulletPoints) complexityScore += 1;
    if (hasCodeBlocks) complexityScore += 2;

    // Map score to complexity
    if (complexityScore >= 5) return 'very-complex';
    if (complexityScore >= 3) return 'complex';
    if (complexityScore >= 2) return 'moderate';
    if (complexityScore >= 1) return 'simple';
    return 'trivial';
  }

  /**
   * Calculate confidence score for classification
   */
  private calculateClassificationConfidence(classification: TaskClassification): number {
    let confidence = 0;
    let factors = 0;

    // Each classification contributes to confidence
    if (classification.type && classification.type !== 'task') {
      confidence += 0.25;
      factors++;
    }

    if (classification.urgency && classification.urgency !== 'normal') {
      confidence += 0.25;
      factors++;
    }

    if (classification.sentiment && classification.sentiment !== 'neutral') {
      confidence += 0.25;
      factors++;
    }

    if (classification.complexity) {
      confidence += 0.25;
      factors++;
    }

    // Base confidence of 0.5 if we have any classification
    if (factors > 0) {
      return 0.5 + confidence;
    }

    return 0.3; // Low confidence if no clear classifications
  }

  /**
   * Get confidence score for a specific classification
   */
  getTypeConfidence(type: TaskClassification['type'], text: string): number {
    if (!type) return 0;

    const pattern = TASK_TYPE_PATTERNS[type];
    if (!pattern) return 0.5;

    // Strong match if pattern found
    if (pattern.test(text)) {
      return 0.9;
    }

    // Weak match based on keywords
    const keywords = text.toLowerCase().split(/\s+/);
    const typeKeywords = pattern.source.toLowerCase().replace(/\\b|[()]/g, '').split('|');
    
    const matches = keywords.filter(k => typeKeywords.some(tk => tk.includes(k)));
    return Math.min(0.3 + (matches.length * 0.1), 0.7);
  }
}