import { injectable } from 'tsyringe';
import { OpenAIService } from '../ai/openai.service';
import { LanguageDetectorService } from './language-detector.service';

/**
 * Translation request interface
 */
export interface TranslationRequest {
  text: string;
  sourceLanguage?: string; // Auto-detect if not provided
  targetLanguage: string;
  context?: string; // Additional context for better translation
  preserveFormatting?: boolean;
}

/**
 * Translation result interface
 */
export interface TranslationResult {
  originalText: string;
  translatedText: string;
  sourceLanguage: string;
  targetLanguage: string;
  confidence: number;
  alternatives?: string[];
}

/**
 * Locale-specific parsing interface
 */
export interface LocaleParsingRules {
  language: string;
  priorityTerms: Map<string, string>;
  datePatterns: RegExp[];
  numberPatterns: RegExp[];
  taskTypeTerms: Map<string, string>;
}

/**
 * Translation and Localization Service
 */
@injectable()
export class TranslationService {
  private localeRules: Map<string, LocaleParsingRules>;
  private translationCache: Map<string, TranslationResult>;

  constructor(
    private openAIService: OpenAIService,
    private languageDetector: LanguageDetectorService,
  ) {
    this.translationCache = new Map();
    this.initializeLocaleRules();
  }

  /**
   * Initialize locale-specific parsing rules
   */
  private initializeLocaleRules(): void {
    this.localeRules = new Map([
      [
        'es',
        {
          language: 'es',
          priorityTerms: new Map([
            ['urgente', 'urgent'],
            ['crítico', 'critical'],
            ['alta', 'high'],
            ['media', 'medium'],
            ['baja', 'low'],
          ]),
          datePatterns: [
            /\b(\d{1,2})\s+de\s+(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre)\s+(?:de\s+)?(\d{4})\b/gi,
            /\b(mañana|hoy|ayer|próxima semana|próximo mes)\b/gi,
          ],
          numberPatterns: [
            /\b(\d{1,3}(?:\.\d{3})*(?:,\d+)?)\b/g, // Spanish number format
          ],
          taskTypeTerms: new Map([
            ['funcionalidad', 'feature'],
            ['característica', 'feature'],
            ['error', 'bug'],
            ['fallo', 'bug'],
            ['mejora', 'improvement'],
            ['documentación', 'documentation'],
            ['prueba', 'test'],
            ['tarea', 'task'],
          ]),
        },
      ],
      [
        'fr',
        {
          language: 'fr',
          priorityTerms: new Map([
            ['urgent', 'urgent'],
            ['critique', 'critical'],
            ['élevée', 'high'],
            ['haute', 'high'],
            ['moyenne', 'medium'],
            ['basse', 'low'],
            ['faible', 'low'],
          ]),
          datePatterns: [
            /\b(\d{1,2})\s+(janvier|février|mars|avril|mai|juin|juillet|août|septembre|octobre|novembre|décembre)\s+(\d{4})\b/gi,
            /\b(demain|aujourd'hui|hier|semaine prochaine|mois prochain)\b/gi,
          ],
          numberPatterns: [
            /\b(\d{1,3}(?:\s\d{3})*(?:,\d+)?)\b/g, // French number format
          ],
          taskTypeTerms: new Map([
            ['fonctionnalité', 'feature'],
            ['bogue', 'bug'],
            ['amélioration', 'improvement'],
            ['documentation', 'documentation'],
            ['test', 'test'],
            ['tâche', 'task'],
          ]),
        },
      ],
      [
        'de',
        {
          language: 'de',
          priorityTerms: new Map([
            ['dringend', 'urgent'],
            ['kritisch', 'critical'],
            ['hoch', 'high'],
            ['mittel', 'medium'],
            ['niedrig', 'low'],
          ]),
          datePatterns: [
            /\b(\d{1,2})\. (Januar|Februar|März|April|Mai|Juni|Juli|August|September|Oktober|November|Dezember) (\d{4})\b/gi,
            /\b(morgen|heute|gestern|nächste Woche|nächster Monat)\b/gi,
          ],
          numberPatterns: [
            /\b(\d{1,3}(?:\.\d{3})*(?:,\d+)?)\b/g, // German number format
          ],
          taskTypeTerms: new Map([
            ['funktion', 'feature'],
            ['fehler', 'bug'],
            ['verbesserung', 'improvement'],
            ['dokumentation', 'documentation'],
            ['test', 'test'],
            ['aufgabe', 'task'],
          ]),
        },
      ],
    ]);
  }

  /**
   * Translate text between languages
   */
  async translate(request: TranslationRequest): Promise<TranslationResult> {
    // Check cache first
    const cacheKey = this.getCacheKey(request);
    if (this.translationCache.has(cacheKey)) {
      return this.translationCache.get(cacheKey)!;
    }

    // Detect source language if not provided
    let sourceLanguage = request.sourceLanguage;
    if (!sourceLanguage) {
      const detection = await this.languageDetector.detectLanguage(request.text);
      sourceLanguage = detection.language;
    }

    // Skip translation if source and target are the same
    if (sourceLanguage === request.targetLanguage) {
      return {
        originalText: request.text,
        translatedText: request.text,
        sourceLanguage,
        targetLanguage: request.targetLanguage,
        confidence: 1.0,
      };
    }

    try {
      // Perform translation using OpenAI
      const result = await this.performTranslation(
        request.text,
        sourceLanguage,
        request.targetLanguage,
        request.context,
        request.preserveFormatting,
      );

      // Cache the result
      this.translationCache.set(cacheKey, result);

      return result;
    } catch (error) {
      console.error('Translation failed:', error);
      // Return original text as fallback
      return {
        originalText: request.text,
        translatedText: request.text,
        sourceLanguage,
        targetLanguage: request.targetLanguage,
        confidence: 0,
      };
    }
  }

  /**
   * Perform the actual translation using OpenAI
   */
  private async performTranslation(
    text: string,
    sourceLanguage: string,
    targetLanguage: string,
    context?: string,
    preserveFormatting?: boolean,
  ): Promise<TranslationResult> {
    const contextInfo = context ? `\nContext: ${context}` : '';
    const formattingInfo = preserveFormatting
      ? '\nPreserve all formatting, line breaks, and special characters.'
      : '';

    const sourceLangConfig = this.languageDetector.getLanguageConfig(sourceLanguage);
    const targetLangConfig = this.languageDetector.getLanguageConfig(targetLanguage);

    const prompt = `Translate the following text from ${sourceLangConfig?.name || sourceLanguage} to ${targetLangConfig?.name || targetLanguage}.${contextInfo}${formattingInfo}

Text to translate:
"${text}"

Provide the translation in a JSON format:
{
  "translation": "translated text here",
  "confidence": 0.95,
  "alternatives": ["alternative translation 1", "alternative translation 2"]
}

Return only the JSON object.`;

    const result = await this.openAIService.complete(
      [{ role: 'user', content: prompt }],
      { maxTokens: Math.min(text.length * 2, 2000), temperature: 0.3 }
    );

    try {
      const parsed = JSON.parse(result.content.trim());
      return {
        originalText: text,
        translatedText: parsed.translation || text,
        sourceLanguage,
        targetLanguage,
        confidence: parsed.confidence || 0.8,
        alternatives: parsed.alternatives || [],
      };
    } catch (error) {
      // Fallback: treat the entire response as the translation
      return {
        originalText: text,
        translatedText: result.content.trim(),
        sourceLanguage,
        targetLanguage,
        confidence: 0.7,
      };
    }
  }

  /**
   * Apply locale-specific parsing rules
   */
  applyLocaleRules(text: string, language: string): {
    normalizedText: string;
    extractedTerms: Map<string, string>;
  } {
    const rules = this.localeRules.get(language);
    if (!rules) {
      return {
        normalizedText: text,
        extractedTerms: new Map(),
      };
    }

    let normalizedText = text;
    const extractedTerms = new Map<string, string>();

    // Normalize priority terms
    for (const [localTerm, englishTerm] of rules.priorityTerms.entries()) {
      const regex = new RegExp(`\\b${localTerm}\\b`, 'gi');
      if (regex.test(normalizedText)) {
        extractedTerms.set('priority', englishTerm);
        normalizedText = normalizedText.replace(regex, englishTerm);
      }
    }

    // Normalize task type terms
    for (const [localTerm, englishTerm] of rules.taskTypeTerms.entries()) {
      const regex = new RegExp(`\\b${localTerm}\\b`, 'gi');
      if (regex.test(normalizedText)) {
        extractedTerms.set('taskType', englishTerm);
        normalizedText = normalizedText.replace(regex, englishTerm);
      }
    }

    return {
      normalizedText,
      extractedTerms,
    };
  }

  /**
   * Parse locale-specific date formats
   */
  parseLocaleDate(dateString: string, language: string): Date | null {
    const months: Record<string, Record<string, number>> = {
      es: {
        enero: 0, febrero: 1, marzo: 2, abril: 3, mayo: 4, junio: 5,
        julio: 6, agosto: 7, septiembre: 8, octubre: 9, noviembre: 10, diciembre: 11,
      },
      fr: {
        janvier: 0, 'février': 1, mars: 2, avril: 3, mai: 4, juin: 5,
        juillet: 6, 'août': 7, septembre: 8, octobre: 9, novembre: 10, 'décembre': 11,
      },
      de: {
        januar: 0, februar: 1, 'märz': 2, april: 3, mai: 4, juni: 5,
        juli: 6, august: 7, september: 8, oktober: 9, november: 10, dezember: 11,
      },
    };

    const languageMonths = months[language];
    if (!languageMonths) {
      return null;
    }

    // Try to parse month names
    for (const [monthName, monthIndex] of Object.entries(languageMonths)) {
      if (dateString.toLowerCase().includes(monthName)) {
        // Extract day and year
        const dayMatch = dateString.match(/\b(\d{1,2})\b/);
        const yearMatch = dateString.match(/\b(\d{4})\b/);
        
        if (dayMatch && yearMatch) {
          const day = parseInt(dayMatch[1]);
          const year = parseInt(yearMatch[1]);
          return new Date(year, monthIndex, day);
        }
      }
    }

    // Handle relative dates
    const today = new Date();
    const relativeDates: Record<string, Record<string, () => Date>> = {
      es: {
        'hoy': () => today,
        'mañana': () => new Date(today.getTime() + 24 * 60 * 60 * 1000),
        'ayer': () => new Date(today.getTime() - 24 * 60 * 60 * 1000),
      },
      fr: {
        "aujourd'hui": () => today,
        'demain': () => new Date(today.getTime() + 24 * 60 * 60 * 1000),
        'hier': () => new Date(today.getTime() - 24 * 60 * 60 * 1000),
      },
      de: {
        'heute': () => today,
        'morgen': () => new Date(today.getTime() + 24 * 60 * 60 * 1000),
        'gestern': () => new Date(today.getTime() - 24 * 60 * 60 * 1000),
      },
    };

    const langRelativeDates = relativeDates[language];
    if (langRelativeDates) {
      for (const [term, dateFunc] of Object.entries(langRelativeDates)) {
        if (dateString.toLowerCase().includes(term)) {
          return dateFunc();
        }
      }
    }

    return null;
  }

  /**
   * Parse locale-specific number formats
   */
  parseLocaleNumber(numberString: string, language: string): number | null {
    const format = this.languageDetector.getNumberFormatForLanguage(language);
    
    // Normalize the number string
    let normalized = numberString;
    
    // Remove thousands separator and replace decimal separator
    if (format.thousands === '.') {
      normalized = normalized.replace(/\./g, '');
    } else if (format.thousands === ',') {
      normalized = normalized.replace(/,/g, '');
    } else if (format.thousands === ' ') {
      normalized = normalized.replace(/\s/g, '');
    }
    
    if (format.decimal === ',') {
      normalized = normalized.replace(',', '.');
    }
    
    const parsed = parseFloat(normalized);
    return isNaN(parsed) ? null : parsed;
  }

  /**
   * Generate cache key for translation request
   */
  private getCacheKey(request: TranslationRequest): string {
    return `${request.sourceLanguage || 'auto'}_${request.targetLanguage}_${request.text.substring(0, 100)}`;
  }

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

  /**
   * Get cache statistics
   */
  getCacheStats(): { size: number } {
    return {
      size: this.translationCache.size,
    };
  }
}