// OpenAI-compatible provider for OpenRouter, LM Studio, Ollama, Groq, xAI, and local endpoints.

import { LLMProvider } from './provider.mjs';

const DEFAULT_BASE_URL = 'https://api.openai.com/v1';

export class OpenAICompatibleProvider extends LLMProvider {
  constructor(config = {}) {
    super(config);
    this.name = config.name || 'openai-compatible';
    this.apiKey = config.apiKey || null;
    this.baseUrl = (config.baseUrl || DEFAULT_BASE_URL).replace(/\/+$/, '');
    this.model = config.model || 'gpt-4o-mini';
    this.temperature = config.temperature ?? 0.2;
    this.maxTokens = config.maxTokens || 2000;
    this.timeoutMs = config.timeoutMs || 90000;
    this.extraHeaders = config.extraHeaders || {};
    this.requiresApiKey = config.requiresApiKey ?? true;
    this.useMaxCompletionTokens = Boolean(config.useMaxCompletionTokens);
  }

  get isConfigured() {
    return Boolean(this.model && (!this.requiresApiKey || this.apiKey));
  }

  get status() {
    if (!this.model) return { state: 'misconfigured', reason: 'LLM_MODEL is required' };
    if (this.requiresApiKey && !this.apiKey) return { state: 'misconfigured', reason: 'LLM_API_KEY is required' };
    return { state: 'configured', provider: this.name, model: this.model, baseUrl: this.baseUrl };
  }

  async complete(systemPrompt, userMessage, opts = {}) {
    const maxTokens = opts.maxTokens || this.maxTokens;
    const timeout = opts.timeout || this.timeoutMs;
    const body = {
      model: this.model,
      temperature: opts.temperature ?? this.temperature,
      messages: [
        { role: 'system', content: systemPrompt },
        { role: 'user', content: userMessage },
      ],
    };
    body[this.useMaxCompletionTokens ? 'max_completion_tokens' : 'max_tokens'] = maxTokens;

    const headers = {
      'Content-Type': 'application/json',
      ...this.extraHeaders,
    };
    if (this.apiKey) headers.Authorization = `Bearer ${this.apiKey}`;

    const res = await fetch(`${this.baseUrl}/chat/completions`, {
      method: 'POST',
      headers,
      body: JSON.stringify(body),
      signal: AbortSignal.timeout(timeout),
    });

    if (!res.ok) {
      const err = await res.text().catch(() => '');
      const detail = err.substring(0, 300);
      if (res.status === 401 || res.status === 403) throw new Error(`${this.name} auth failed (${res.status}): ${detail}`);
      if (res.status === 408 || res.status === 429) throw new Error(`${this.name} rate limited or timed out (${res.status}): ${detail}`);
      throw new Error(`${this.name} API ${res.status}: ${detail}`);
    }

    const data = await res.json();
    const text = data.choices?.[0]?.message?.content || data.choices?.[0]?.text || '';
    return {
      text,
      usage: {
        inputTokens: data.usage?.prompt_tokens || data.usage?.input_tokens || 0,
        outputTokens: data.usage?.completion_tokens || data.usage?.output_tokens || 0,
      },
      model: data.model || this.model,
    };
  }
}
