import { injectable } from 'tsyringe';
import { OpenAIService } from '../ai/openai.service';

/**
 * Supported languages configuration
 */
export interface LanguageConfig {
  code: string; // ISO 639-1 code
  name: string;
  nativeName: string;
  supported: boolean;
  dateFormats: string[];
  numberFormat: {
    decimal: string;
    thousands: string;
  };
}

/**
 * Language detection result
 */
export interface LanguageDetectionResult {
  language: string;
  confidence: number;
  alternatives?: Array<{ language: string; confidence: number }>;
}

/**
 * Language Detector Service for multi-language support
 */
@injectable()
export class LanguageDetectorService {
  private supportedLanguages: Map<string, LanguageConfig>;
  private languagePatterns: Map<string, RegExp[]>;

  constructor(private openAIService: OpenAIService) {
    this.initializeSupportedLanguages();
    this.initializeLanguagePatterns();
  }

  /**
   * Initialize supported languages configuration
   */
  private initializeSupportedLanguages(): void {
    this.supportedLanguages = new Map([
      [
        'en',
        {
          code: 'en',
          name: 'English',
          nativeName: 'English',
          supported: true,
          dateFormats: ['MM/DD/YYYY', 'MMM DD, YYYY', 'DD MMM YYYY'],
          numberFormat: { decimal: '.', thousands: ',' },
        },
      ],
      [
        'es',
        {
          code: 'es',
          name: 'Spanish',
          nativeName: 'Español',
          supported: true,
          dateFormats: ['DD/MM/YYYY', 'DD de MMM de YYYY'],
          numberFormat: { decimal: ',', thousands: '.' },
        },
      ],
      [
        'fr',
        {
          code: 'fr',
          name: 'French',
          nativeName: 'Français',
          supported: true,
          dateFormats: ['DD/MM/YYYY', 'DD MMM YYYY'],
          numberFormat: { decimal: ',', thousands: ' ' },
        },
      ],
      [
        'de',
        {
          code: 'de',
          name: 'German',
          nativeName: 'Deutsch',
          supported: true,
          dateFormats: ['DD.MM.YYYY', 'DD. MMM YYYY'],
          numberFormat: { decimal: ',', thousands: '.' },
        },
      ],
      [
        'pt',
        {
          code: 'pt',
          name: 'Portuguese',
          nativeName: 'Português',
          supported: true,
          dateFormats: ['DD/MM/YYYY', 'DD de MMM de YYYY'],
          numberFormat: { decimal: ',', thousands: '.' },
        },
      ],
      [
        'it',
        {
          code: 'it',
          name: 'Italian',
          nativeName: 'Italiano',
          supported: true,
          dateFormats: ['DD/MM/YYYY', 'DD MMM YYYY'],
          numberFormat: { decimal: ',', thousands: '.' },
        },
      ],
      [
        'zh',
        {
          code: 'zh',
          name: 'Chinese',
          nativeName: '中文',
          supported: true,
          dateFormats: ['YYYY年MM月DD日', 'YYYY-MM-DD'],
          numberFormat: { decimal: '.', thousands: ',' },
        },
      ],
      [
        'ja',
        {
          code: 'ja',
          name: 'Japanese',
          nativeName: '日本語',
          supported: true,
          dateFormats: ['YYYY年MM月DD日', 'YYYY/MM/DD'],
          numberFormat: { decimal: '.', thousands: ',' },
        },
      ],
    ]);
  }

  /**
   * Initialize language-specific patterns for detection
   */
  private initializeLanguagePatterns(): void {
    this.languagePatterns = new Map([
      // English patterns
      [
        'en',
        [
          /\b(the|and|of|to|in|for|with|on|at|by|from|as|is|was|are|were|be|have|has|had|do|does|did)\b/gi,
          /\b(task|feature|bug|priority|deadline|assigned|create|update|delete)\b/gi,
        ],
      ],
      // Spanish patterns
      [
        'es',
        [
          /\b(el|la|los|las|un|una|de|en|por|para|con|sin|sobre|entre|hasta|desde|es|son|está|están)\b/gi,
          /\b(tarea|función|error|prioridad|fecha límite|asignado|crear|actualizar|eliminar)\b/gi,
        ],
      ],
      // French patterns
      [
        'fr',
        [
          /\b(le|la|les|un|une|de|du|des|en|pour|avec|sans|sur|entre|jusqu|depuis|est|sont|être|avoir)\b/gi,
          /\b(tâche|fonctionnalité|bogue|priorité|échéance|assigné|créer|mettre à jour|supprimer)\b/gi,
        ],
      ],
      // German patterns
      [
        'de',
        [
          /\b(der|die|das|ein|eine|von|zu|mit|ohne|auf|zwischen|bis|seit|ist|sind|haben|werden)\b/gi,
          /\b(Aufgabe|Funktion|Fehler|Priorität|Frist|zugewiesen|erstellen|aktualisieren|löschen)\b/gi,
        ],
      ],
      // Portuguese patterns
      [
        'pt',
        [
          /\b(o|a|os|as|um|uma|de|em|por|para|com|sem|sobre|entre|até|desde|é|são|está|estão)\b/gi,
          /\b(tarefa|funcionalidade|erro|prioridade|prazo|atribuído|criar|atualizar|excluir)\b/gi,
        ],
      ],
      // Italian patterns
      [
        'it',
        [
          /\b(il|la|i|le|un|una|di|da|in|per|con|senza|su|tra|fino|da|è|sono|essere|avere)\b/gi,
          /\b(compito|funzionalità|errore|priorità|scadenza|assegnato|creare|aggiornare|eliminare)\b/gi,
        ],
      ],
      // Chinese patterns (simplified)
      [
        'zh',
        [
          /[\u4e00-\u9fff]+/g, // Chinese characters
          /[任务|功能|错误|优先级|截止日期|分配|创建|更新|删除]/g,
        ],
      ],
      // Japanese patterns
      [
        'ja',
        [
          /[\u3040-\u309f\u30a0-\u30ff]+/g, // Hiragana and Katakana
          /[タスク|機能|バグ|優先度|期限|割り当て|作成|更新|削除]/g,
        ],
      ],
    ]);
  }

  /**
   * Detect language of input text
   */
  async detectLanguage(text: string): Promise<LanguageDetectionResult> {
    // First try pattern-based detection
    const patternResult = this.detectByPatterns(text);
    
    // If high confidence from patterns, return immediately
    if (patternResult.confidence > 0.8) {
      return patternResult;
    }

    // Use AI for more accurate detection
    try {
      const aiResult = await this.detectWithAI(text);
      
      // Combine results for better accuracy
      if (aiResult.language === patternResult.language) {
        return {
          language: aiResult.language,
          confidence: Math.min((aiResult.confidence + patternResult.confidence) / 2 + 0.1, 1.0),
          alternatives: aiResult.alternatives,
        };
      }
      
      // AI result takes precedence if different
      return aiResult;
    } catch (error) {
      console.error('AI language detection failed:', error);
      return patternResult;
    }
  }

  /**
   * Detect language using pattern matching
   */
  private detectByPatterns(text: string): LanguageDetectionResult {
    const scores = new Map<string, number>();
    
    // Check each language's patterns
    for (const [lang, patterns] of this.languagePatterns.entries()) {
      let score = 0;
      let totalMatches = 0;
      
      for (const pattern of patterns) {
        const matches = text.match(pattern);
        if (matches) {
          totalMatches += matches.length;
        }
      }
      
      // Normalize score based on text length
      score = totalMatches / Math.max(text.split(/\s+/).length, 1);
      scores.set(lang, score);
    }
    
    // Find the best match
    let bestLang = 'en'; // Default to English
    let bestScore = 0;
    const alternatives: Array<{ language: string; confidence: number }> = [];
    
    for (const [lang, score] of scores.entries()) {
      if (score > bestScore) {
        if (bestScore > 0) {
          alternatives.push({ language: bestLang, confidence: Math.min(bestScore, 1.0) });
        }
        bestScore = score;
        bestLang = lang;
      } else if (score > 0) {
        alternatives.push({ language: lang, confidence: Math.min(score, 1.0) });
      }
    }
    
    return {
      language: bestLang,
      confidence: Math.min(bestScore, 1.0),
      alternatives: alternatives.sort((a, b) => b.confidence - a.confidence).slice(0, 3),
    };
  }

  /**
   * Detect language using OpenAI
   */
  private async detectWithAI(text: string): Promise<LanguageDetectionResult> {
    const supportedCodes = Array.from(this.supportedLanguages.keys()).join(', ');
    
    const prompt = `Detect the language of the following text and return a JSON object with the language code (ISO 639-1), confidence score (0-1), and up to 3 alternative languages with their confidence scores.

Supported languages: ${supportedCodes}

Text: "${text.substring(0, 500)}"

Return format:
{
  "language": "en",
  "confidence": 0.95,
  "alternatives": [
    {"language": "es", "confidence": 0.05}
  ]
}

Return only the JSON object, no additional text.`;

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

    try {
      const parsed = JSON.parse(result.content.trim());
      
      // Validate the response
      if (!parsed.language || !this.supportedLanguages.has(parsed.language)) {
        return {
          language: 'en',
          confidence: 0.5,
        };
      }
      
      return {
        language: parsed.language,
        confidence: parsed.confidence || 0.8,
        alternatives: parsed.alternatives || [],
      };
    } catch (error) {
      console.error('Failed to parse AI language detection result:', error);
      return {
        language: 'en',
        confidence: 0.5,
      };
    }
  }

  /**
   * Get language configuration
   */
  getLanguageConfig(languageCode: string): LanguageConfig | undefined {
    return this.supportedLanguages.get(languageCode);
  }

  /**
   * Check if a language is supported
   */
  isLanguageSupported(languageCode: string): boolean {
    const config = this.supportedLanguages.get(languageCode);
    return config?.supported || false;
  }

  /**
   * Get all supported languages
   */
  getSupportedLanguages(): LanguageConfig[] {
    return Array.from(this.supportedLanguages.values()).filter(lang => lang.supported);
  }

  /**
   * Parse locale-specific date format
   */
  getDateFormatsForLanguage(languageCode: string): string[] {
    const config = this.supportedLanguages.get(languageCode);
    return config?.dateFormats || ['MM/DD/YYYY', 'YYYY-MM-DD'];
  }

  /**
   * Get number format for language
   */
  getNumberFormatForLanguage(languageCode: string): { decimal: string; thousands: string } {
    const config = this.supportedLanguages.get(languageCode);
    return config?.numberFormat || { decimal: '.', thousands: ',' };
  }
}