import { useState, useCallback } from "react"; import { useTranslation } from "react-i18next"; import { toast } from "sonner"; import { configApi } from "@/lib/api"; import { useCommonConfigBase, type UseCommonConfigBaseReturn, } from "@/hooks/useCommonConfigBase"; import { codexAdapter, preserveCodexConfigFormat, } from "@/hooks/commonConfigAdapters"; import { extractTomlDifference } from "@/utils/tomlConfigMerge"; import type { ProviderMeta } from "@/types"; interface UseCodexCommonConfigProps { /** * 当前 Codex 配置(可能是纯 TOML 或 JSON wrapper 格式) */ codexConfig: string; /** * 配置变化回调 */ onConfigChange: (config: string) => void; /** * 初始数据(编辑模式) */ initialData?: { settingsConfig?: Record; meta?: ProviderMeta; }; /** * 当前选中的预设 ID */ selectedPresetId?: string; /** * 当前正在编辑的供应商 ID */ currentProviderId?: string; } export interface UseCodexCommonConfigReturn { /** 是否启用通用配置 */ useCommonConfig: boolean; /** 通用配置片段 (TOML 格式) */ commonConfigSnippet: string; /** 通用配置错误信息 */ commonConfigError: string; /** 是否正在加载 */ isLoading: boolean; /** 是否正在提取 */ isExtracting: boolean; /** 通用配置开关处理函数 */ handleCommonConfigToggle: (checked: boolean) => void; /** 通用配置片段变化处理函数 */ handleCommonConfigSnippetChange: (snippet: string) => void; /** 从当前配置提取通用配置 */ handleExtract: () => Promise; /** 最终配置(运行时合并结果,只读) */ finalConfig: string; /** 是否有待保存的通用配置变更 */ hasUnsavedCommonConfig: boolean; /** 获取待保存的通用配置片段(用于 handleSubmit) */ getPendingCommonConfigSnippet: () => string | null; /** 标记通用配置已保存 */ markCommonConfigSaved: () => void; } /** * 管理 Codex 通用配置片段 * * 基于 useCommonConfigBase 泛型 Hook + Codex TOML 适配器实现。 * 额外处理 Codex 双格式(纯 TOML / JSON wrapper)的写回逻辑。 */ export function useCodexCommonConfig({ codexConfig, onConfigChange, initialData, selectedPresetId, }: UseCodexCommonConfigProps): UseCodexCommonConfigReturn { const { t } = useTranslation(); // 额外的 isExtracting 状态(base hook 的 handleExtract 不适用于 Codex) const [localIsExtracting, setLocalIsExtracting] = useState(false); const [localExtractError, setLocalExtractError] = useState(""); const base: UseCommonConfigBaseReturn = useCommonConfigBase({ adapter: codexAdapter, inputValue: codexConfig, onInputChange: onConfigChange, initialData, selectedPresetId, }); // Codex 自定义 handleExtract:处理双格式写回 + 状态管理 const handleExtract = useCallback(async () => { setLocalIsExtracting(true); setLocalExtractError(""); try { const request = codexAdapter.buildExtractRequest(base.finalValue); const extracted = await configApi.extractCommonConfigSnippet( "codex", request, ); if (!extracted || !extracted.trim()) { setLocalExtractError(t("codexConfig.extractNoCommonConfig")); return; } // 验证 TOML 格式 const parseResult = codexAdapter.parseSnippet(extracted); if (parseResult.error || parseResult.config === null) { setLocalExtractError( t("codexConfig.extractedTomlInvalid", { defaultValue: "提取的配置 TOML 格式错误", }), ); return; } // 从 config 中移除与 extracted 相同的部分 const customToml = codexAdapter.parseInput(codexConfig); const diffResult = extractTomlDifference(customToml, extracted); if (diffResult.error) { // 差异提取失败,显示错误而不是静默吞掉 setLocalExtractError( t("codexConfig.extractDiffFailed", { error: diffResult.error, defaultValue: `差异提取失败: ${diffResult.error}`, }), ); return; } // 更新 snippet 状态(在差异提取成功后再更新,避免状态不一致) base.handleCommonConfigSnippetChange(extracted); // 使用共享的格式保留函数写回 const preserveResult = preserveCodexConfigFormat( codexConfig, diffResult.customToml, ); if (preserveResult.error) { // 格式保留失败,显示错误 setLocalExtractError( t("codexConfig.preserveFormatFailed", { error: preserveResult.error, defaultValue: `配置格式保留失败: ${preserveResult.error}`, }), ); return; } onConfigChange(preserveResult.config); toast.success( t("codexConfig.extractSuccessNeedSave", { defaultValue: "已提取通用配置,点击保存按钮完成保存", }), ); } catch (error) { console.error("提取 Codex 通用配置失败:", error); setLocalExtractError( t("codexConfig.extractFailed", { error: String(error), defaultValue: "提取失败", }), ); } finally { setLocalIsExtracting(false); } }, [base, codexConfig, onConfigChange, t]); // 合并 error:优先显示 extract 错误,其次是 base 的错误 const combinedError = localExtractError || base.commonConfigError; return { useCommonConfig: base.useCommonConfig, commonConfigSnippet: base.commonConfigSnippet, commonConfigError: combinedError, isLoading: base.isLoading, isExtracting: localIsExtracting, handleCommonConfigToggle: base.handleCommonConfigToggle, handleCommonConfigSnippetChange: base.handleCommonConfigSnippetChange, handleExtract, finalConfig: base.finalValue, hasUnsavedCommonConfig: base.hasUnsavedCommonConfig, getPendingCommonConfigSnippet: base.getPendingCommonConfigSnippet, markCommonConfigSaved: base.markCommonConfigSaved, }; }