/**
 * Google Gemini LLM provider.
 *
 * Uses Google's Generative Language API (not OpenAI-compatible).
 * Reads config from GEMINI_API_KEY, GEMINI_MODEL.
 */

import type {
  ChatCompletionRequest,
  ChatCompletionResponse,
  ChatMessage,
  LLMProvider,
} from '../types.js';
import { getMessageText } from '../types.js';

export interface GeminiConfig {
  apiKey: string;
  model?: string;
}

interface GeminiPart {
  text: string;
}

interface GeminiContent {
  role: 'user' | 'model';
  parts: GeminiPart[];
}

export class GeminiProvider implements LLMProvider {
  private config: GeminiConfig;

  constructor(config?: Partial<GeminiConfig>) {
    this.config = {
      apiKey: config?.apiKey ?? process.env.GEMINI_API_KEY ?? '',
      model: config?.model ?? process.env.GEMINI_MODEL ?? 'gemini-1.5-flash',
    };
  }

  isConfigured(): boolean {
    return Boolean(this.config.apiKey);
  }

  async chatCompletion(req: ChatCompletionRequest): Promise<ChatCompletionResponse> {
    if (!this.isConfigured()) {
      throw new Error('Gemini is not configured (missing GEMINI_API_KEY)');
    }

    const model = req.model || this.config.model!;
    const url = `https://generativelanguage.googleapis.com/v1beta/models/${encodeURIComponent(model)}:generateContent?key=${this.config.apiKey}`;

    const { systemInstruction, contents } = this.convertMessages(req.messages);

    const body: Record<string, unknown> = { contents };
    if (systemInstruction) {
      body.systemInstruction = { parts: [{ text: systemInstruction }] };
    }
    if (req.temperature !== undefined) {
      body.generationConfig = { temperature: req.temperature };
    }

    const response = await fetch(url, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(body),
    });

    if (!response.ok) {
      const text = await response.text();
      throw new Error(`Gemini error ${response.status}: ${text}`);
    }

    const data = (await response.json()) as {
      candidates: Array<{
        content: { parts: GeminiPart[] };
        finishReason: string;
      }>;
      usageMetadata?: {
        promptTokenCount: number;
        candidatesTokenCount: number;
        totalTokenCount: number;
      };
    };

    const content = data.candidates[0]?.content?.parts?.map(p => p.text).join('') ?? '';
    const finishReason = data.candidates[0]?.finishReason;

    return {
      content,
      model,
      finishReason:
        finishReason === 'STOP' ? 'stop' : finishReason === 'MAX_TOKENS' ? 'length' : null,
      usage: {
        promptTokens: data.usageMetadata?.promptTokenCount ?? 0,
        completionTokens: data.usageMetadata?.candidatesTokenCount ?? 0,
        totalTokens: data.usageMetadata?.totalTokenCount ?? 0,
      },
    };
  }

  private convertMessages(messages: ChatMessage[]): {
    systemInstruction: string | null;
    contents: GeminiContent[];
  } {
    const systemMessages = messages.filter(m => m.role === 'system');
    const systemInstruction = systemMessages.map(m => getMessageText(m)).join('\n') || null;

    const contents: GeminiContent[] = messages
      .filter(m => m.role !== 'system')
      .map(m => ({
        role: (m.role === 'assistant' ? 'model' : 'user') as 'user' | 'model',
        parts: [{ text: getMessageText(m) }],
      }));

    // Gemini requires at least one user turn
    if (contents.length === 0) {
      contents.push({ role: 'user', parts: [{ text: '' }] });
    }

    return { systemInstruction, contents };
  }
}
