// src/services/ai/aiService.ts
import { config } from '../../config/appConfig.js';
import { logger } from '../logger.js';

export interface AIRequest {
  prompt: string;
  maxTokens?: number;
  temperature?: number;
  context?: string;
}

export interface AIResponse {
  content: string;
  requestTimeMs: number;
  tokenCount?: number;
}

export class AIService {
  private readonly endpoint: string;
  private readonly apiKey: string;
  private readonly model: string;

  constructor() {
    this.endpoint = config.ai.endpoint;
    this.apiKey = config.ai.apiKey;
    this.model = config.ai.model;
    
    logger.info('ai-service', 'AI Service initialized', {
      model: this.model,
      hasApiKey: !!this.apiKey
    });
  }

  async call(request: AIRequest): Promise<AIResponse> {
    const startTime = Date.now();
    const timerId = logger.time('ai-service', `call-${request.context || 'unknown'}`);
    
    try {
      const headers: Record<string, string> = {
        'Content-Type': 'application/json'
      };
      
      if (this.apiKey) {
        headers['Authorization'] = `Bearer ${this.apiKey}`;
      }
      
      const requestBody = {
        model: this.model,
        messages: [{ role: 'user', content: request.prompt }],
        max_tokens: request.maxTokens || 1500,
        temperature: request.temperature || 0.3
      };

      logger.debug('ai-service', 'Making AI request', {
        context: request.context,
        promptLength: request.prompt.length,
        maxTokens: requestBody.max_tokens,
        temperature: requestBody.temperature
      });

      const response = await fetch(`${this.endpoint}/v1/chat/completions`, {
        method: 'POST',
        headers,
        body: JSON.stringify(requestBody)
      });

      const requestTimeMs = Date.now() - startTime;
      logger.timeEnd(timerId);

      if (!response.ok) {
        const errorText = await response.text();
        logger.error('ai-service', 'AI API request failed', new Error(`HTTP ${response.status}`), {
          status: response.status,
          context: request.context,
          errorText: errorText.slice(0, 200)
        });
        throw new Error(`AI API error: ${response.status} - ${errorText}`);
      }

      const data = await response.json();
      const content = data.choices?.[0]?.message?.content;
      
      if (!content) {
        logger.error('ai-service', 'No response content from AI model', undefined, {
          context: request.context,
          choices: data.choices?.length || 0
        });
        throw new Error('No response from AI model');
      }

      logger.info('ai-service', 'AI request completed', {
        context: request.context,
        responseLength: content.length,
        duration: `${requestTimeMs}ms`,
        success: true
      });

      return {
        content: content.trim(),
        requestTimeMs,
        tokenCount: data.usage?.total_tokens
      };
      
    } catch (error) {
      const requestTimeMs = Date.now() - startTime;
      logger.error('ai-service', 'AI service call failed', error as Error, {
        context: request.context,
        duration: `${requestTimeMs}ms`
      });
      throw error;
    }
  }

  async callMicroTask(prompt: string, context: string, maxTokens: number = 500): Promise<AIResponse> {
    return this.call({
      prompt,
      maxTokens,
      temperature: 0.3,
      context: `micro-task:${context}`
    });
  }

  estimateTokens(text: string): number {
    // Simple estimation: ~4 characters per token
    return Math.ceil(text.length / 4);
  }

  validatePromptSize(prompt: string, maxTokens: number = config.ai.maxPromptTokens): boolean {
    const estimatedTokens = this.estimateTokens(prompt);
    if (estimatedTokens > maxTokens) {
      logger.warn('ai-service', 'Prompt exceeds token limit', {
        estimated: estimatedTokens,
        limit: maxTokens,
        promptLength: prompt.length
      });
      return false;
    }
    return true;
  }

  // Utility for parsing JSON responses with error handling
  parseJSONResponse<T>(response: string, fallback: T): T {
    try {
      let cleaned = response.trim();
      
      // Remove markdown code blocks
      const jsonBlockPatterns = [
        /```json\s*([\s\S]*?)\s*```/i,
        /```\s*([\s\S]*?)\s*```/i,
        /\{[\s\S]*\}/,
      ];
      
      for (const pattern of jsonBlockPatterns) {
        const match = cleaned.match(pattern);
        if (match) {
          cleaned = match[1] || match[0];
          break;
        }
      }
      
      // Handle truncated JSON
      if (!cleaned.endsWith('}') && !cleaned.endsWith(']')) {
        logger.warn('ai-service', 'JSON appears truncated, attempting recovery');
        
        let braceCount = 0;
        let bracketCount = 0;
        let inString = false;
        let escaped = false;
        let lastCompleteStructure = '';
        
        for (let i = 0; i < cleaned.length; i++) {
          const char = cleaned[i];
          
          if (escaped) {
            escaped = false;
            continue;
          }
          
          if (char === '\\') {
            escaped = true;
            continue;
          }
          
          if (char === '"' && !escaped) {
            inString = !inString;
            continue;
          }
          
          if (!inString) {
            if (char === '{') braceCount++;
            if (char === '}') braceCount--;
            if (char === '[') bracketCount++;
            if (char === ']') bracketCount--;
            
            if (braceCount === 0 && bracketCount === 0 && (char === '}' || char === ']')) {
              lastCompleteStructure = cleaned.substring(0, i + 1);
            }
          }
        }
        
        if (lastCompleteStructure) {
          cleaned = lastCompleteStructure;
        } else {
          if (braceCount > 0) cleaned += '}';
          if (bracketCount > 0) cleaned += ']';
        }
      }
      
      const parsed = JSON.parse(cleaned);
      
      logger.debug('ai-service', 'JSON parsing successful', {
        originalLength: response.length,
        cleanedLength: cleaned.length
      });
      
      return parsed;
      
    } catch (error) {
      logger.warn('ai-service', 'JSON parsing failed, using fallback', {
        error: (error as Error).message,
        responsePreview: response.slice(0, 100)
      });
      return fallback;
    }
  }
}

export const aiService = new AIService();