/**
 * GeminiTranslationProvider — Gemini OpenAI-compat REST endpoint.
 *
 * Pricing constants (provisional — gemini-3.1-flash-lite GA, as of 2026-05):
 *   Input:  $0.075 / 1M tokens
 *   Output: $0.30  / 1M tokens
 * Update DEFAULT_INPUT_USD_PER_MTOK / DEFAULT_OUTPUT_USD_PER_MTOK when rates change.
 */

import type { TranslationProvider, TranslationRequest, TranslationResponse } from './types.js';
import { TranslationProviderError } from './types.js';
import { captureCaught } from '@/server/observability/capture.server';

const ENDPOINT = 'https://generativelanguage.googleapis.com/v1beta/openai/chat/completions';

/** Provisional rates for gemini-3.1-flash-lite GA (USD per million tokens). */
export const DEFAULT_INPUT_USD_PER_MTOK = 0.075;
export const DEFAULT_OUTPUT_USD_PER_MTOK = 0.3;

export class GeminiTranslationProvider implements TranslationProvider {
  readonly id = 'gemini';

  constructor(
    private readonly apiKey: string,
    private readonly modelId: string,
    private readonly inputUsdPerMTok: number = DEFAULT_INPUT_USD_PER_MTOK,
    private readonly outputUsdPerMTok: number = DEFAULT_OUTPUT_USD_PER_MTOK,
  ) {}

  async translateBatch(req: TranslationRequest): Promise<TranslationResponse> {
    const systemPrompt = buildSystemPrompt(req);

    let res: Response;
    try {
      res = await fetch(ENDPOINT, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          Authorization: `Bearer ${this.apiKey}`,
        },
        body: JSON.stringify({
          model: this.modelId,
          messages: [
            { role: 'system', content: systemPrompt },
            { role: 'user', content: JSON.stringify(req.texts) },
          ],
          response_format: { type: 'json_object' },
        }),
      });
    } catch (err) {
      captureCaught(err, { scope: 'translation.gemini.fetch', severity: 'warning' });
      throw new TranslationProviderError('transport', `Network error: ${String(err)}`);
    }

    if (res.status === 401 || res.status === 403) {
      throw new TranslationProviderError('auth', `Gemini auth failed: HTTP ${res.status}`);
    }
    if (res.status === 429) {
      throw new TranslationProviderError('rate_limit', 'Gemini rate limit exceeded');
    }
    if (res.status >= 500) {
      throw new TranslationProviderError('transport', `Gemini server error: HTTP ${res.status}`);
    }
    if (!res.ok) {
      throw new TranslationProviderError(
        'transport',
        `Gemini unexpected status: HTTP ${res.status}`,
      );
    }

    let body: unknown;
    try {
      body = await res.json();
    } catch (err) {
      captureCaught(err, { scope: 'translation.gemini.json-parse', severity: 'warning' });
      throw new TranslationProviderError('transport', 'Gemini returned non-JSON body');
    }

    const choice = (
      body as { choices?: Array<{ message?: { content?: string }; finish_reason?: string }> }
    )?.choices?.[0];

    if (choice?.finish_reason === 'content_filter') {
      throw new TranslationProviderError('content_filter', 'Gemini content filter triggered');
    }

    const raw = choice?.message?.content;
    if (!raw) {
      throw new TranslationProviderError('invalid_response', 'Gemini returned empty content');
    }

    let translations: unknown;
    try {
      const parsed = JSON.parse(raw) as unknown;
      // Accept either a bare array or an object wrapping an array (Gemini json_object mode)
      if (Array.isArray(parsed)) {
        translations = parsed;
      } else if (parsed && typeof parsed === 'object') {
        const vals = Object.values(parsed as Record<string, unknown>);
        if (vals.length === 1 && Array.isArray(vals[0])) {
          translations = vals[0];
        } else {
          translations = parsed;
        }
      }
    } catch (err) {
      captureCaught(err, { scope: 'translation.gemini.content-parse', severity: 'warning' });
      throw new TranslationProviderError('invalid_response', 'Gemini content is not valid JSON');
    }

    if (!Array.isArray(translations) || translations.length !== req.texts.length) {
      throw new TranslationProviderError(
        'invalid_response',
        `Expected array of length ${req.texts.length}, got ${Array.isArray(translations) ? translations.length : typeof translations}`,
      );
    }

    const usage = (body as { usage?: { prompt_tokens?: number; completion_tokens?: number } })
      ?.usage;
    const inputTokens = usage?.prompt_tokens ?? 0;
    const outputTokens = usage?.completion_tokens ?? 0;
    const costUsd =
      (inputTokens * this.inputUsdPerMTok + outputTokens * this.outputUsdPerMTok) / 1_000_000;

    return {
      translations: translations as string[],
      inputTokens,
      outputTokens,
      costUsd,
      modelId: this.modelId,
    };
  }
}

function buildSystemPrompt(req: TranslationRequest): string {
  let prompt =
    `Translate the following array of strings from ${req.sourceLocale} to ${req.targetLocale}. ` +
    `Preserve formatting, marketing tone, numbers, product names. ` +
    `Return JSON array of translated strings in the same order.`;

  if (req.glossary && req.glossary.length > 0) {
    const terms = req.glossary.map((g) => `  "${g.source}" → "${g.translation}"`).join('\n');
    prompt += `\n\nGlossary (use these translations exactly):\n${terms}`;
  }

  return prompt;
}
