import { ref } from 'vue' import { useI18n } from 'vue-i18n' import { useAppStore } from '@/stores/app' import { adminAPI } from '@/api/admin' export interface GeminiTokenInfo { access_token?: string refresh_token?: string token_type?: string scope?: string expires_at?: number | string project_id?: string [key: string]: unknown } export function useGeminiOAuth() { const appStore = useAppStore() const { t } = useI18n() const authUrl = ref('') const sessionId = ref('') const state = ref('') const loading = ref(false) const error = ref('') const resetState = () => { authUrl.value = '' sessionId.value = '' state.value = '' loading.value = false error.value = '' } const generateAuthUrl = async ( proxyId: number | null | undefined, redirectUri: string ): Promise => { loading.value = true authUrl.value = '' sessionId.value = '' state.value = '' error.value = '' try { if (!redirectUri?.trim()) { error.value = t('admin.accounts.oauth.gemini.missingRedirectUri') appStore.showError(error.value) return false } const payload: Record = { redirect_uri: redirectUri.trim() } if (proxyId) payload.proxy_id = proxyId const response = await adminAPI.gemini.generateAuthUrl(payload as any) authUrl.value = response.auth_url sessionId.value = response.session_id state.value = response.state return true } catch (err: any) { error.value = err.response?.data?.detail || t('admin.accounts.oauth.gemini.failedToGenerateUrl') appStore.showError(error.value) return false } finally { loading.value = false } } const exchangeAuthCode = async (params: { code: string sessionId: string state: string redirectUri: string proxyId?: number | null }): Promise => { const code = params.code?.trim() if (!code || !params.sessionId || !params.state || !params.redirectUri?.trim()) { error.value = t('admin.accounts.oauth.gemini.missingExchangeParams') return null } loading.value = true error.value = '' try { const payload: Record = { session_id: params.sessionId, state: params.state, code, redirect_uri: params.redirectUri.trim() } if (params.proxyId) payload.proxy_id = params.proxyId const tokenInfo = await adminAPI.gemini.exchangeCode(payload as any) return tokenInfo as GeminiTokenInfo } catch (err: any) { error.value = err.response?.data?.detail || t('admin.accounts.oauth.gemini.failedToExchangeCode') appStore.showError(error.value) return null } finally { loading.value = false } } const buildCredentials = (tokenInfo: GeminiTokenInfo): Record => { let expiresAt: string | undefined if (typeof tokenInfo.expires_at === 'number' && Number.isFinite(tokenInfo.expires_at)) { expiresAt = Math.floor(tokenInfo.expires_at).toString() } else if (typeof tokenInfo.expires_at === 'string' && tokenInfo.expires_at.trim()) { expiresAt = tokenInfo.expires_at.trim() } return { access_token: tokenInfo.access_token, refresh_token: tokenInfo.refresh_token, token_type: tokenInfo.token_type, expires_at: expiresAt, scope: tokenInfo.scope, project_id: tokenInfo.project_id } } return { authUrl, sessionId, state, loading, error, resetState, generateAuthUrl, exchangeAuthCode, buildCredentials } }