/**
 * @license
 * Copyright 2025 OElite Platform
 * SPDX-License-Identifier: Apache-2.0
 */
/* eslint-disable @typescript-eslint/no-explicit-any */
import { BaseProvider } from './baseProvider.js';
import { ProviderType } from './types.js';
import { GOOGLE_MODELS } from './modelCatalog.js';
/**
 * Google Gemini provider implementation
 * Supports both API key and OAuth authentication
 */
export class GoogleProvider extends BaseProvider {
    static DEFAULT_BASE_URL = 'https://generativelanguage.googleapis.com';
    static API_VERSION = 'v1beta';
    constructor(config) {
        super({
            ...config,
            type: ProviderType.GOOGLE,
            baseUrl: config.baseUrl || GoogleProvider.DEFAULT_BASE_URL,
        });
    }
    async doInitialize() {
        // Check for OAuth tokens first, then API key
        const hasOAuth = this.isUsingGeminiOAuth();
        const apiKey = this.getEffectiveApiKey();
        if (!hasOAuth && !apiKey) {
            throw new Error('Google authentication not configured. Please set GEMINI_API_KEY or GOOGLE_API_KEY, or use OAuth authentication');
        }
        if (hasOAuth) {
            console.log('Gemini OAuth detected - using OAuth authentication');
        }
        else {
            console.log('Google API key detected - using API key authentication');
        }
    }
    /**
     * Check if using Gemini OAuth
     */
    isUsingGeminiOAuth() {
        return (!!process.env['GEMINI_OAUTH_TOKEN'] ||
            !!process.env['GEMINI_REFRESH_TOKEN'] ||
            !!process.env['GEMINI_ACCESS_TOKEN'] ||
            !!process.env['GOOGLE_OAUTH_TOKEN'] ||
            !!process.env['GOOGLE_REFRESH_TOKEN'] ||
            !!process.env['GOOGLE_ACCESS_TOKEN']);
    }
    isConfigured() {
        const apiKey = this.getEffectiveApiKey();
        const hasGeminiOAuth = this.isUsingGeminiOAuth();
        return !!apiKey || hasGeminiOAuth;
    }
    async getAvailableModels() {
        return GOOGLE_MODELS;
    }
    async doHealthCheck() {
        // Simple health check - try to get models
        await this.getAvailableModels();
    }
    /**
     * Get auth headers for Google API
     */
    async getAuthHeaders() {
        // Check for OAuth token first
        const oauthToken = process.env['GEMINI_OAUTH_TOKEN'] ||
            process.env['GEMINI_ACCESS_TOKEN'] ||
            process.env['GOOGLE_OAUTH_TOKEN'] ||
            process.env['GOOGLE_ACCESS_TOKEN'];
        if (oauthToken) {
            return {
                Authorization: `Bearer ${oauthToken}`,
            };
        }
        // Fall back to API key
        const apiKey = this.getEffectiveApiKey();
        if (apiKey) {
            // Google uses API key as query parameter, not header
            return {};
        }
        throw new Error('No authentication method available for Google provider');
    }
    /**
     * Get API endpoint with authentication
     */
    getApiUrl(model, endpoint) {
        const baseUrl = this.getEffectiveBaseUrl();
        const apiKey = this.getEffectiveApiKey();
        // If using API key, add it as query parameter
        if (apiKey && !this.isUsingGeminiOAuth()) {
            return `${baseUrl}/${GoogleProvider.API_VERSION}/models/${model}:${endpoint}?key=${apiKey}`;
        }
        // If using OAuth, don't add API key
        return `${baseUrl}/${GoogleProvider.API_VERSION}/models/${model}:${endpoint}`;
    }
    /**
     * Format messages for Google Gemini API
     */
    formatMessages(messages) {
        return messages.map((msg) => ({
            role: msg.role === 'assistant' ? 'model' : msg.role,
            parts: [{ text: msg.content }],
        }));
    }
    async createCompletion(model, messages, options) {
        await this.validateModel(model);
        const headers = await this.getAuthHeaders();
        const url = this.getApiUrl(model, 'generateContent');
        const response = await fetch(url, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                ...headers,
                ...this.config.customHeaders,
            },
            body: JSON.stringify({
                contents: this.formatMessages(messages),
                generationConfig: {
                    temperature: options?.temperature,
                    topP: options?.top_p,
                    topK: options?.top_k,
                    maxOutputTokens: options?.max_tokens || 2048,
                },
            }),
        });
        if (!response.ok) {
            const error = await response.text();
            throw new Error(`Google API error: ${response.status} - ${error}`);
        }
        return await response.json();
    }
    async *createStreamingCompletion(model, messages, options) {
        await this.validateModel(model);
        const headers = await this.getAuthHeaders();
        const url = this.getApiUrl(model, 'streamGenerateContent');
        const response = await fetch(url, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                ...headers,
                ...this.config.customHeaders,
            },
            body: JSON.stringify({
                contents: this.formatMessages(messages),
                generationConfig: {
                    temperature: options?.temperature,
                    topP: options?.top_p,
                    topK: options?.top_k,
                    maxOutputTokens: options?.max_tokens || 2048,
                },
            }),
        });
        if (!response.ok) {
            const error = await response.text();
            throw new Error(`Google API error: ${response.status} - ${error}`);
        }
        if (!response.body) {
            throw new Error('No response body from Google API');
        }
        const reader = response.body.getReader();
        const decoder = new TextDecoder();
        try {
            while (true) {
                const { done, value } = await reader.read();
                if (done)
                    break;
                const chunk = decoder.decode(value, { stream: true });
                const lines = chunk.split('\n').filter((line) => line.trim());
                for (const line of lines) {
                    try {
                        const json = JSON.parse(line);
                        yield json;
                    }
                    catch {
                        // Skip invalid JSON lines
                    }
                }
            }
        }
        finally {
            reader.releaseLock();
        }
    }
}
//# sourceMappingURL=googleProvider.js.map