/**
 * Accuracy Tracker Service
 * 
 * Learns from actual translation results to improve estimation accuracy
 */

import { PrismaClient } from '@prisma/client';
import { logger } from '../utils/logger';

const prisma = new PrismaClient();

export class AccuracyTracker {
  
  /**
   * Record a completed translation for ML learning
   * 
   * Called after every successful translation
   */
  async recordUsage(
    targetLang: string,
    estimatedTokens: number,
    actualTokens: number,
    htmlComplexity: 'none' | 'light' | 'medium' | 'heavy'
  ): Promise<void> {
    try {
      // Insert record into translation_records
      await prisma.$executeRaw`
        INSERT INTO translation_records 
        (target_lang, estimated_tokens, actual_tokens, html_complexity)
        VALUES (${targetLang}, ${estimatedTokens}, ${actualTokens}, ${htmlComplexity})
      `;
      
      // Update ML adjustment ratio
      await this.updateMLAdjustment(targetLang);
      
      logger.info('Recorded translation for ML learning', {
        targetLang,
        estimatedTokens,
        actualTokens,
        error: actualTokens - estimatedTokens,
        errorPercent: ((actualTokens - estimatedTokens) / estimatedTokens * 100).toFixed(2) + '%',
      });
    } catch (error) {
      logger.error('Failed to record translation usage', { error });
    }
  }
  
  /**
   * Update ML adjustment ratio based on historical data
   * 
   * Uses last 100 translations to calculate average error
   */
  async updateMLAdjustment(targetLang: string): Promise<void> {
    try {
      // Calculate average error from last 100 records
      const stats = await prisma.$queryRaw<Array<{
        sample_count: number;
        avg_error_percent: number;
        avg_ratio: number;
      }>>`
        SELECT 
          COUNT(*) as sample_count,
          AVG((actual_tokens - estimated_tokens) / estimated_tokens * 100) as avg_error_percent,
          AVG(actual_tokens / estimated_tokens) as avg_ratio
        FROM (
          SELECT estimated_tokens, actual_tokens
          FROM translation_records
          WHERE target_lang = ${targetLang}
          ORDER BY created_at DESC
          LIMIT 100
        ) recent
      `;
      
      if (!stats || stats.length === 0) return;
      
      const { sample_count, avg_error_percent, avg_ratio } = stats[0];
      
      // Calculate ML adjustment ratio
      // If we're consistently over/under-estimating, adjust accordingly
      let mlAdjustment = avg_ratio;
      
      // Clamp adjustment to reasonable range (0.80 - 1.20)
      mlAdjustment = Math.max(0.80, Math.min(1.20, mlAdjustment));
      
      // Update or insert accuracy_stats
      await prisma.$executeRaw`
        INSERT INTO accuracy_stats (language, sample_count, avg_error_percent, ml_adjustment_ratio)
        VALUES (${targetLang}, ${sample_count}, ${avg_error_percent}, ${mlAdjustment})
        ON DUPLICATE KEY UPDATE
          sample_count = ${sample_count},
          avg_error_percent = ${avg_error_percent},
          ml_adjustment_ratio = ${mlAdjustment},
          updated_at = CURRENT_TIMESTAMP
      `;
      
      logger.info('Updated ML adjustment', {
        targetLang,
        sample_count,
        avg_error_percent,
        mlAdjustment,
      });
    } catch (error) {
      logger.error('Failed to update ML adjustment', { targetLang, error });
    }
  }
  
  /**
   * Get accuracy statistics for one or all languages
   */
  async getAccuracyStats(lang?: string): Promise<Array<{
    language: string;
    sample_count: number;
    avg_error_percent: number;
    ml_adjustment_ratio: number;
    status: 'learning' | 'trained' | 'accurate';
  }>> {
    try {
      let stats;
      
      if (lang) {
        stats = await prisma.$queryRaw<Array<{
          language: string;
          sample_count: number;
          avg_error_percent: number;
          ml_adjustment_ratio: number;
        }>>`
          SELECT language, sample_count, avg_error_percent, ml_adjustment_ratio
          FROM accuracy_stats
          WHERE language = ${lang}
          ORDER BY sample_count DESC
        `;
      } else {
        stats = await prisma.$queryRaw<Array<{
          language: string;
          sample_count: number;
          avg_error_percent: number;
          ml_adjustment_ratio: number;
        }>>`
          SELECT language, sample_count, avg_error_percent, ml_adjustment_ratio
          FROM accuracy_stats
          WHERE sample_count > 0
          ORDER BY sample_count DESC
        `;
      }
      
      // Add status based on sample count and error
      return stats.map(stat => ({
        ...stat,
        status: this.getStatus(stat.sample_count, stat.avg_error_percent),
      }));
    } catch (error) {
      logger.error('Failed to get accuracy stats', { error });
      return [];
    }
  }
  
  /**
   * Determine training status
   */
  private getStatus(sampleCount: number, avgError: number): 'learning' | 'trained' | 'accurate' {
    if (sampleCount < 10) return 'learning';
    if (sampleCount < 100 || Math.abs(avgError) > 10) return 'trained';
    return 'accurate';
  }
}

export const accuracyTracker = new AccuracyTracker();
