/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
import {} from 'google-auth-library';
import { HybridTokenStorage } from '../mcp/token-storage/hybrid-token-storage.js';
import { OAUTH_FILE } from '../config/storage.js';
import * as path from 'node:path';
import * as os from 'node:os';
import { promises as fs } from 'node:fs';
import { GEMINI_DIR } from '../utils/paths.js';
import { coreEvents } from '../utils/events.js';
const KEYCHAIN_SERVICE_NAME = 'gemini-cli-oauth';
const MAIN_ACCOUNT_KEY = 'main-account';
export class OAuthCredentialStorage {
    static storage = new HybridTokenStorage(KEYCHAIN_SERVICE_NAME);
    /**
     * Load cached OAuth credentials
     */
    static async loadCredentials() {
        try {
            const credentials = await this.storage.getCredentials(MAIN_ACCOUNT_KEY);
            if (credentials?.token) {
                const { accessToken, refreshToken, expiresAt, tokenType, scope } = credentials.token;
                // Convert from OAuthCredentials format to Google Credentials format
                const googleCreds = {
                    access_token: accessToken,
                    refresh_token: refreshToken || undefined,
                    token_type: tokenType || undefined,
                    scope: scope || undefined,
                };
                if (expiresAt) {
                    googleCreds.expiry_date = expiresAt;
                }
                return googleCreds;
            }
            // Fallback: Try to migrate from old file-based storage
            return await this.migrateFromFileStorage();
        }
        catch (error) {
            coreEvents.emitFeedback('error', 'Failed to load OAuth credentials', error);
            throw new Error('Failed to load OAuth credentials', { cause: error });
        }
    }
    /**
     * Save OAuth credentials
     */
    static async saveCredentials(credentials) {
        if (!credentials.access_token) {
            throw new Error('Attempted to save credentials without an access token.');
        }
        // Convert Google Credentials to OAuthCredentials format
        const mcpCredentials = {
            serverName: MAIN_ACCOUNT_KEY,
            token: {
                accessToken: credentials.access_token,
                refreshToken: credentials.refresh_token || undefined,
                tokenType: credentials.token_type || 'Bearer',
                scope: credentials.scope || undefined,
                expiresAt: credentials.expiry_date || undefined,
            },
            updatedAt: Date.now(),
        };
        await this.storage.setCredentials(mcpCredentials);
    }
    /**
     * Clear cached OAuth credentials
     */
    static async clearCredentials() {
        try {
            await this.storage.deleteCredentials(MAIN_ACCOUNT_KEY);
            // Also try to remove the old file if it exists
            const oldFilePath = path.join(os.homedir(), GEMINI_DIR, OAUTH_FILE);
            await fs.rm(oldFilePath, { force: true }).catch(() => { });
        }
        catch (error) {
            coreEvents.emitFeedback('error', 'Failed to clear OAuth credentials', error);
            throw new Error('Failed to clear OAuth credentials', { cause: error });
        }
    }
    /**
     * Migrate credentials from old file-based storage to keychain
     */
    static async migrateFromFileStorage() {
        const oldFilePath = path.join(os.homedir(), GEMINI_DIR, OAUTH_FILE);
        let credsJson;
        try {
            credsJson = await fs.readFile(oldFilePath, 'utf-8');
        }
        catch (error) {
            if (typeof error === 'object' &&
                error !== null &&
                'code' in error &&
                error.code === 'ENOENT') {
                // File doesn't exist, so no migration.
                return null;
            }
            // Other read errors should propagate.
            throw error;
        }
        const credentials = JSON.parse(credsJson);
        // Save to new storage
        await this.saveCredentials(credentials);
        // Remove old file after successful migration
        await fs.rm(oldFilePath, { force: true }).catch(() => { });
        return credentials;
    }
}
//# sourceMappingURL=oauth-credential-storage.js.map