/**
 * Groq Provider - chat completions via Groq's OpenAI-compatible API
 */

export const GROQ_BASE_URL = 'https://api.groq.com/openai/v1';

export const MODELS = {
  LARGE: 'openai/gpt-oss-120b',
  SMALL: 'openai/gpt-oss-20b',
};

export class GroqProvider {
  constructor({ apiKey, baseUrl = GROQ_BASE_URL, timeoutMs = 30000 }) {
    if (!apiKey) {
      throw new Error('Groq API key is required');
    }
    this.apiKey = apiKey;
    this.baseUrl = baseUrl;
    this.timeoutMs = timeoutMs;
  }

  async chatCompletion({
    messages,
    model = MODELS.LARGE,
    temperature = 0.3,
    maxTokens = 500,
    responseFormat = null,
    timeoutMs = this.timeoutMs,
  }) {
    const started = Date.now();
    const body = {
      model,
      messages,
      temperature,
      max_completion_tokens: maxTokens,
    };
    if (responseFormat?.type === 'json_object') {
      body.response_format = { type: 'json_object' };
    }

    console.log('[Groq] Request:', {
      model: body.model,
      temperature: body.temperature,
      maxTokens: body.max_completion_tokens,
      hasResponseFormat: !!body.response_format,
      messageCount: body.messages?.length,
      systemPromptLength: body.messages?.[0]?.content?.length,
      userPromptLength: body.messages?.[1]?.content?.length,
    });

    const response = await this._makeRequest('chat/completions', body, timeoutMs);

    console.log('[Groq] Raw response:', {
      hasChoices: !!response.choices,
      choicesLength: response.choices?.length,
      firstChoice: response.choices?.[0] ? {
        finishReason: response.choices[0].finish_reason,
        hasMessage: !!response.choices[0].message,
        contentLength: response.choices[0].message?.content?.length,
        contentPreview: response.choices[0].message?.content?.substring(0, 200),
      } : null,
      usage: response.usage,
      model: response.model,
    });

    const content = response.choices?.[0]?.message?.content || '';
    const usage = response.usage || {};

    let parsed = null;
    if (responseFormat && content) {
      try {
        parsed = JSON.parse(content);
      } catch {
        parsed = this._extractJson(content);
      }
    }

    return {
      content,
      parsed,
      usage: {
        promptTokens: usage.prompt_tokens || 0,
        completionTokens: usage.completion_tokens || 0,
        totalTokens: usage.total_tokens || 0,
      },
      latencyMs: Date.now() - started,
      model: response.model || model,
    };
  }

  _extractJson(content) {
    const codeBlockMatch = content.match(/```(?:json)?\s*([\s\S]*?)```/);
    if (codeBlockMatch) {
      try { return JSON.parse(codeBlockMatch[1].trim()); } catch { /* fall through */ }
    }
    const jsonMatch = content.match(/(\{[\s\S]*\}|\[[\s\S]*\])/);
    if (jsonMatch) {
      try { return JSON.parse(jsonMatch[1]); } catch { /* fall through */ }
    }
    return null;
  }

  async _makeRequest(endpoint, body, timeoutMs) {
    const controller = new AbortController();
    const timeout = setTimeout(() => controller.abort(), timeoutMs);
    try {
      const response = await fetch(`${this.baseUrl}/${endpoint}`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${this.apiKey}`,
        },
        body: JSON.stringify(body),
        signal: controller.signal,
      });
      if (!response.ok) {
        const error = await response.json().catch(() => ({}));
        const message = error.error?.message || `Groq API error: ${response.status}`;
        const err = new Error(message);
        err.status = response.status;
        err.code = error.error?.code;
        if (error.error?.failed_generation) {
          err.failedGeneration = error.error.failed_generation;
          console.error('[Groq] JSON validation failed. Model output:', error.error.failed_generation);
        }
        throw err;
      }
      return response.json();
    } catch (error) {
      if (error.name === 'AbortError') {
        const err = new Error(`Groq request timed out after ${timeoutMs}ms`);
        err.code = 'TIMEOUT';
        throw err;
      }
      throw error;
    } finally {
      clearTimeout(timeout);
    }
  }

  isConfigured() {
    return !!this.apiKey;
  }
}
