import crypto from 'node:crypto';
import { Agent, fetch as undiciFetch } from 'undici';

export const CUSTOM_PROVIDER_ID = '__custom__';

export const LLM_PROVIDER_CATALOG = [
  {
    id: CUSTOM_PROVIDER_ID,
    label: '自定义 OpenAI 兼容',
    kind: 'custom',
    apiKeyEnv: null,
    defaultModel: '',
    models: [],
  },
  {
    id: 'custom_deepseek',
    label: 'DeepSeek',
    kind: 'builtin',
    apiKeyEnv: 'DEEPSEEK_API_KEY',
    defaultModel: 'deepseek-chat',
    models: ['deepseek-chat', 'deepseek-reasoner'],
  },
  {
    id: 'openai',
    label: 'OpenAI',
    kind: 'builtin',
    apiKeyEnv: 'OPENAI_API_KEY',
    defaultModel: 'gpt-4o',
    models: ['gpt-4o', 'gpt-4o-mini'],
  },
  {
    id: 'openrouter',
    label: 'OpenRouter',
    kind: 'builtin',
    apiKeyEnv: 'OPENROUTER_API_KEY',
    defaultModel: 'anthropic/claude-sonnet-4',
    models: ['anthropic/claude-sonnet-4', 'openai/gpt-4o'],
  },
  {
    id: 'anthropic',
    label: 'Anthropic',
    kind: 'builtin',
    apiKeyEnv: 'ANTHROPIC_API_KEY',
    defaultModel: 'claude-sonnet-4-20250514',
    models: ['claude-sonnet-4-20250514', 'claude-3-5-haiku-20241022'],
  },
];

const catalogById = Object.fromEntries(LLM_PROVIDER_CATALOG.map((item) => [item.id, item]));

const insecureDispatcher = new Agent({
  connect: { rejectUnauthorized: false },
});

function resolveEncryptionKey(explicitKey) {
  const raw =
    explicitKey ??
    process.env.H5_SETTINGS_ENCRYPTION_KEY ??
    process.env.TKMIND_SERVER__SECRET_KEY ??
    'local-dev-secret';
  return crypto.createHash('sha256').update(raw).digest();
}

export function encryptSecret(plaintext, encryptionKey) {
  const key = resolveEncryptionKey(encryptionKey);
  const iv = crypto.randomBytes(12);
  const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
  const encrypted = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);
  return {
    ciphertext: encrypted.toString('base64'),
    iv: iv.toString('base64'),
    tag: cipher.getAuthTag().toString('base64'),
  };
}

export function decryptSecret({ ciphertext, iv, tag }, encryptionKey) {
  const key = resolveEncryptionKey(encryptionKey);
  const decipher = crypto.createDecipheriv('aes-256-gcm', key, Buffer.from(iv, 'base64'));
  decipher.setAuthTag(Buffer.from(tag, 'base64'));
  const plain = Buffer.concat([
    decipher.update(Buffer.from(ciphertext, 'base64')),
    decipher.final(),
  ]);
  return plain.toString('utf8');
}

export function maskApiKey(apiKey) {
  if (!apiKey) return '';
  if (apiKey.length <= 8) return '*'.repeat(apiKey.length);
  const head = apiKey.slice(0, 4);
  const tail = apiKey.slice(-4);
  return `${head}${'*'.repeat(Math.max(apiKey.length - 8, 4))}${tail}`;
}

export function parseModelList(raw) {
  if (Array.isArray(raw)) {
    return [...new Set(raw.map((item) => String(item).trim()).filter(Boolean))];
  }
  return [
    ...new Set(
      String(raw ?? '')
        .split(/[\n,]/)
        .map((item) => item.trim())
        .filter(Boolean),
    ),
  ];
}

export function normalizeApiUrl(raw) {
  const trimmed = String(raw ?? '').trim();
  if (!trimmed) return '';
  if (/^https?:\/\//i.test(trimmed)) return trimmed.replace(/\/+$/, '');
  return `http://${trimmed.replace(/\/+$/, '')}`;
}

export function resolveChatCompletionsUrl(apiUrl) {
  const normalized = normalizeApiUrl(apiUrl);
  if (!normalized) return '';
  if (normalized.endsWith('/chat/completions')) return normalized;
  if (normalized.endsWith('/v1')) return `${normalized}/chat/completions`;
  return `${normalized}/chat/completions`;
}

export const RELAY_BOOTSTRAP = {
  name: process.env.H5_RELAY_BOOTSTRAP_NAME ?? 'Relay Buyer Ollama',
  apiUrl:
    process.env.H5_RELAY_BOOTSTRAP_URL ??
    'http://127.0.0.1:18300/relay/buyer/v1/chat/completions',
  apiKey:
    process.env.H5_RELAY_BOOTSTRAP_API_KEY ??
    'UqyHPKSSEZq0-oPnl8sru-7hZcJ2anPUL1yAVk866Vo',
  models: parseModelList(process.env.H5_RELAY_BOOTSTRAP_MODELS ?? 'qwen2.5:3b'),
  defaultModel: process.env.H5_RELAY_BOOTSTRAP_MODEL ?? 'qwen2.5:3b',
  relayProvider: process.env.H5_RELAY_BOOTSTRAP_PROVIDER ?? 'ollama',
};

export const LOCAL_LLM_FALLBACK = {
  enabled: process.env.H5_LOCAL_LLM_FALLBACK !== '0',
  providerId: process.env.H5_LOCAL_LLM_PROVIDER_ID ?? 'custom_local_ollama_7b',
  displayName: process.env.H5_LOCAL_LLM_NAME ?? 'Local Ollama 7B',
  apiUrl:
    process.env.H5_LOCAL_LLM_URL ?? 'http://127.0.0.1:11434/v1/chat/completions',
  apiKey: process.env.H5_LOCAL_LLM_API_KEY ?? 'ollama',
  model: process.env.H5_LOCAL_LLM_MODEL ?? 'qwen2.5:3b',
};

let cachedLocalFallbackProviderId = null;

export async function testRelayConnection(
  { apiUrl, apiKey, model, relayProvider },
  fetchImpl = undiciFetch,
) {
  const url = resolveChatCompletionsUrl(apiUrl);
  if (!url) return { ok: false, message: 'API 地址无效' };
  if (!apiKey) return { ok: false, message: '缺少 API Key' };
  if (!model) return { ok: false, message: '缺少模型' };

  const started = Date.now();
  const body = {
    model,
    messages: [{ role: 'user', content: 'Hello' }],
    stream: false,
    ...(relayProvider ? { provider: relayProvider } : {}),
  };

  const upstream = await fetchImpl(url, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Authorization: `Bearer ${apiKey}`,
    },
    body: JSON.stringify(body),
    dispatcher: url.startsWith('https://') ? insecureDispatcher : undefined,
  });
  const latencyMs = Date.now() - started;
  const text = await upstream.text().catch(() => '');
  if (!upstream.ok) {
    let detail = text.slice(0, 500) || '(空响应)';
    if (detail === '{}') {
      detail = '空 JSON 响应';
    }
    const statusHint =
      upstream.status === 401
        ? 'Bearer Token 无效或已过期'
        : upstream.status === 404
          ? '地址不存在，请检查 API URL'
          : upstream.status === 400
            ? '请求参数被拒绝，请检查 model / provider'
            : `HTTP ${upstream.status}`;
    return {
      ok: false,
      latencyMs,
      message: `Relay ${upstream.status} ${statusHint}：${detail}`,
    };
  }

  let data;
  try {
    data = JSON.parse(text);
  } catch {
    return { ok: false, latencyMs, message: '响应不是 JSON' };
  }

  const reply =
    data?.choices?.[0]?.message?.content ??
    data?.message?.content ??
    data?.output ??
    null;
  return {
    ok: true,
    latencyMs,
    model,
    reply: reply ? String(reply).slice(0, 300) : '(联通成功，无文本内容)',
  };
}

export async function testLocalLlmConnection(fetchImpl = undiciFetch) {
  if (!LOCAL_LLM_FALLBACK.enabled) {
    return { ok: false, message: '本地 LLM fallback 已禁用' };
  }
  return testRelayConnection(
    {
      apiUrl: LOCAL_LLM_FALLBACK.apiUrl,
      apiKey: LOCAL_LLM_FALLBACK.apiKey,
      model: LOCAL_LLM_FALLBACK.model,
      relayProvider: null,
    },
    fetchImpl,
  );
}

function parseModelsJson(raw) {
  if (!raw) return [];
  try {
    const parsed = JSON.parse(raw);
    return Array.isArray(parsed) ? parseModelList(parsed) : [];
  } catch {
    return [];
  }
}

function rowToPublic(row, catalogItem, apiKeyForMask) {
  const providerKind = row.provider_kind ?? 'builtin';
  const models =
    providerKind === 'custom'
      ? parseModelsJson(row.models_json)
      : (catalogItem?.models ?? []);
  return {
    id: row.id,
    providerId: row.provider_id,
    providerKind,
    providerLabel:
      providerKind === 'custom'
        ? row.name
        : (catalogItem?.label ?? row.provider_id),
    name: row.name,
    defaultModel: row.default_model,
    models,
    apiUrl: row.api_url ?? null,
    basePath: row.base_path ?? null,
    engine: row.engine ?? 'openai',
    relayProvider: row.relay_provider ?? null,
    goosedProviderId: row.goosed_provider_id ?? null,
    status: row.status,
    isSelected: Boolean(row.is_selected),
    apiKeyMasked: maskApiKey(apiKeyForMask),
    createdAt: Number(row.created_at),
    updatedAt: Number(row.updated_at),
  };
}

function profileFromRow(row, decryptRow) {
  const providerKind = row.provider_kind ?? 'builtin';
  const models =
    providerKind === 'custom'
      ? parseModelsJson(row.models_json)
      : [row.default_model];
  return {
    providerKind,
    providerId: row.provider_id,
    goosedProviderId: row.goosed_provider_id ?? null,
    name: row.name,
    defaultModel: row.default_model,
    apiKey: decryptRow(row),
    apiUrl: row.api_url ?? null,
    basePath: row.base_path ?? null,
    engine: row.engine ?? 'openai',
    relayProvider: row.relay_provider ?? null,
    models,
  };
}

async function goosedApiFetch(apiTarget, apiSecret, pathname, init = {}, fetchImpl = undiciFetch) {
  const url = new URL(pathname, apiTarget);
  const headers = {
    ...(init.headers ?? {}),
    'X-Secret-Key': apiSecret,
  };
  if (init.body && !headers['Content-Type']) {
    headers['Content-Type'] = 'application/json';
  }
  const dispatcher = apiTarget.startsWith('https://') ? insecureDispatcher : undefined;
  return fetchImpl(url, { ...init, headers, dispatcher });
}

async function writeGoosedConfig(apiTarget, apiSecret, key, value, isSecret, fetchImpl) {
  const upstream = await goosedApiFetch(
    apiTarget,
    apiSecret,
    '/config/upsert',
    {
      method: 'POST',
      body: JSON.stringify({ key, value, is_secret: isSecret }),
    },
    fetchImpl,
  );
  if (upstream.ok) return { ok: true, skipped: false };
  if (upstream.status === 404) return { ok: false, skipped: true };
  const text = await upstream.text().catch(() => '');
  throw new Error(`同步 TKMind Agent 配置 ${key} 失败: ${text || upstream.status}`);
}

export async function ensureLocalFallbackProviderOnGoosed(
  apiTarget,
  apiSecret,
  fetchImpl = undiciFetch,
) {
  if (!LOCAL_LLM_FALLBACK.enabled) {
    throw new Error('本地 LLM fallback 已禁用');
  }
  const profile = {
    providerKind: 'custom',
    name: LOCAL_LLM_FALLBACK.displayName,
    apiUrl: LOCAL_LLM_FALLBACK.apiUrl,
    apiKey: LOCAL_LLM_FALLBACK.apiKey,
    models: [LOCAL_LLM_FALLBACK.model],
    defaultModel: LOCAL_LLM_FALLBACK.model,
    goosedProviderId: cachedLocalFallbackProviderId,
    engine: 'openai',
  };
  const goosedProviderId = await upsertCustomProviderOnGoosed(
    apiTarget,
    apiSecret,
    profile,
    fetchImpl,
  );
  cachedLocalFallbackProviderId = goosedProviderId;
  return goosedProviderId;
}

export async function updateSessionProvider(
  apiFetchImpl,
  sessionId,
  provider,
  model,
) {
  const upstream = await apiFetchImpl('/agent/update_provider', {
    method: 'POST',
    body: JSON.stringify({
      session_id: sessionId,
      provider,
      model,
    }),
  });
  if (!upstream.ok) {
    const text = await upstream.text().catch(() => '');
    throw new Error(text || `切换会话 Provider 失败: ${upstream.status}`);
  }
}

async function upsertCustomProviderOnGoosed(apiTarget, apiSecret, profile, fetchImpl) {
  const headers = profile.relayProvider
    ? { 'X-Provider': profile.relayProvider }
    : undefined;
  const body = {
    engine: profile.engine || 'openai',
    display_name: profile.name,
    api_url: profile.apiUrl,
    api_key: profile.apiKey,
    models: profile.models,
    supports_streaming: true,
    requires_auth: true,
    ...(profile.basePath ? { base_path: profile.basePath } : {}),
    ...(headers ? { headers } : {}),
  };

  if (profile.goosedProviderId) {
    const upstream = await goosedApiFetch(
      apiTarget,
      apiSecret,
      `/config/custom-providers/${encodeURIComponent(profile.goosedProviderId)}`,
      { method: 'PUT', body: JSON.stringify(body) },
      fetchImpl,
    );
    if (!upstream.ok) {
      const text = await upstream.text().catch(() => '');
      throw new Error(`更新 TKMind Agent 自定义 provider 失败: ${text || upstream.status}`);
    }
    return profile.goosedProviderId;
  }

  const upstream = await goosedApiFetch(
    apiTarget,
    apiSecret,
    '/config/custom-providers',
    { method: 'POST', body: JSON.stringify(body) },
    fetchImpl,
  );
  if (!upstream.ok) {
    const text = await upstream.text().catch(() => '');
    throw new Error(`创建 TKMind Agent 自定义 provider 失败: ${text || upstream.status}`);
  }
  const data = await upstream.json();
  return data.provider_name;
}

async function removeCustomProviderOnGoosed(apiTarget, apiSecret, goosedProviderId, fetchImpl) {
  if (!goosedProviderId) return;
  const upstream = await goosedApiFetch(
    apiTarget,
    apiSecret,
    `/config/custom-providers/${encodeURIComponent(goosedProviderId)}`,
    { method: 'DELETE' },
    fetchImpl,
  );
  if (!upstream.ok && upstream.status !== 404) {
    const text = await upstream.text().catch(() => '');
    throw new Error(`删除 TKMind Agent 自定义 provider 失败: ${text || upstream.status}`);
  }
}

async function syncBuiltinProfileToGoosed(apiTarget, apiSecret, profile, fetchImpl) {
  const catalogItem = catalogById[profile.providerId];
  if (!catalogItem?.apiKeyEnv) {
    throw new Error(`未知内置 provider: ${profile.providerId}`);
  }
  await writeGoosedConfig(
    apiTarget,
    apiSecret,
    catalogItem.apiKeyEnv,
    profile.apiKey,
    true,
    fetchImpl,
  );
  await writeGoosedConfig(
    apiTarget,
    apiSecret,
    'GOOSE_PROVIDER',
    profile.providerId,
    false,
    fetchImpl,
  );
  await writeGoosedConfig(
    apiTarget,
    apiSecret,
    'GOOSE_MODEL',
    profile.defaultModel,
    false,
    fetchImpl,
  );
  await writeGoosedConfig(
    apiTarget,
    apiSecret,
    'TKMIND_PROVIDER',
    profile.providerId,
    false,
    fetchImpl,
  );
  await writeGoosedConfig(
    apiTarget,
    apiSecret,
    'TKMIND_MODEL',
    profile.defaultModel,
    false,
    fetchImpl,
  );
}

export async function syncProfileToGoosed(apiTarget, apiSecret, profile, fetchImpl = undiciFetch) {
  if (profile.providerKind === 'custom') {
    const goosedProviderId = await upsertCustomProviderOnGoosed(
      apiTarget,
      apiSecret,
      profile,
      fetchImpl,
    );
    await writeGoosedConfig(
      apiTarget,
      apiSecret,
      'GOOSE_PROVIDER',
      goosedProviderId,
      false,
      fetchImpl,
    );
    await writeGoosedConfig(
      apiTarget,
      apiSecret,
      'GOOSE_MODEL',
      profile.defaultModel,
      false,
      fetchImpl,
    );
    await writeGoosedConfig(
      apiTarget,
      apiSecret,
      'TKMIND_PROVIDER',
      goosedProviderId,
      false,
      fetchImpl,
    );
    await writeGoosedConfig(
      apiTarget,
      apiSecret,
      'TKMIND_MODEL',
      profile.defaultModel,
      false,
      fetchImpl,
    );
    return goosedProviderId;
  }

  await syncBuiltinProfileToGoosed(apiTarget, apiSecret, profile, fetchImpl);
  return profile.providerId;
}

function isCustomPayload(payload) {
  return payload?.providerId === CUSTOM_PROVIDER_ID || payload?.providerKind === 'custom';
}

function validateCustomPayload(payload) {
  const name = String(payload?.name ?? '').trim();
  const apiKey = String(payload?.apiKey ?? '').trim();
  const apiUrl = normalizeApiUrl(payload?.apiUrl);
  const models = parseModelList(payload?.models);
  const defaultModel = String(payload?.defaultModel ?? '').trim() || models[0] || '';
  if (!name) return { ok: false, message: '请填写配置名称' };
  if (!apiUrl) return { ok: false, message: '请填写 API 地址' };
  if (!apiKey) return { ok: false, message: '请填写 API Key / Bearer Token' };
  if (models.length === 0) return { ok: false, message: '请至少填写一个模型' };
  if (!models.includes(defaultModel)) {
    return { ok: false, message: '默认模型必须在模型列表中' };
  }
  return {
    ok: true,
    value: {
      name,
      apiKey,
      apiUrl,
      models,
      defaultModel,
      basePath: String(payload?.basePath ?? '').trim() || null,
      engine: String(payload?.engine ?? 'openai').trim() || 'openai',
      relayProvider: String(payload?.relayProvider ?? '').trim() || null,
    },
  };
}

export function createLlmProviderService(
  pool,
  { apiTarget, apiSecret, encryptionKey, apiFetchImpl = undiciFetch } = {},
) {
  function catalogItem(providerId) {
    return catalogById[providerId] ?? null;
  }

  function decryptRow(row) {
    return decryptSecret(
      {
        ciphertext: row.api_key_ciphertext,
        iv: row.api_key_iv,
        tag: row.api_key_tag,
      },
      encryptionKey,
    );
  }

  async function getRowById(id) {
    const [rows] = await pool.query('SELECT * FROM h5_llm_provider_keys WHERE id = ? LIMIT 1', [
      id,
    ]);
    return rows[0] ?? null;
  }

  async function getSelectedRow() {
    const [rows] = await pool.query(
      'SELECT * FROM h5_llm_provider_keys WHERE is_selected = 1 AND status = ? LIMIT 1',
      ['active'],
    );
    return rows[0] ?? null;
  }

  async function clearSelected() {
    await pool.query('UPDATE h5_llm_provider_keys SET is_selected = 0, updated_at = ?', [
      Date.now(),
    ]);
  }

  async function syncRow(row, fetchImpl = apiFetchImpl) {
    const profile = profileFromRow(row, decryptRow);
    const goosedProviderId = await syncProfileToGoosed(
      apiTarget,
      apiSecret,
      profile,
      fetchImpl,
    );
    if (profile.providerKind === 'custom' && goosedProviderId !== row.goosed_provider_id) {
      await pool.query(
        'UPDATE h5_llm_provider_keys SET goosed_provider_id = ?, provider_id = ?, updated_at = ? WHERE id = ?',
        [goosedProviderId, goosedProviderId, Date.now(), row.id],
      );
    }
    return goosedProviderId;
  }

  async function testSelectedRow(row) {
    const profile = profileFromRow(row, decryptRow);
    if (profile.providerKind === 'custom') {
      try {
        return await testRelayConnection(
          {
            apiUrl: profile.apiUrl,
            apiKey: profile.apiKey,
            model: profile.defaultModel,
            relayProvider: profile.relayProvider,
          },
          apiFetchImpl,
        );
      } catch (err) {
        return {
          ok: false,
          message: err instanceof Error ? err.message : String(err),
        };
      }
    }
    return { ok: true, model: profile.defaultModel };
  }

  async function resolveSelectedProvider(fetchImpl = apiFetchImpl) {
    const row = await getSelectedRow();
    if (!row) {
      return { ok: false, message: '请先启用 LLM 配置' };
    }
    const profile = profileFromRow(row, decryptRow);
    const selectedTest = await testSelectedRow(row);
    if (!selectedTest.ok) {
      return {
        ok: false,
        message: selectedTest.message ?? '当前选中的 LLM 不可用',
      };
    }
    try {
      const goosedProviderId = await syncRow(row, fetchImpl);
      const providerId =
        profile.providerKind === 'custom'
          ? (goosedProviderId ?? profile.goosedProviderId ?? profile.providerId)
          : profile.providerId;
      return {
        ok: true,
        providerId,
        model: profile.defaultModel,
        source: 'selected',
      };
    } catch (err) {
      return {
        ok: false,
        message: err instanceof Error ? err.message : '同步 LLM 配置失败',
      };
    }
  }

  /** Local fallback is only for DeepSeek creditsExhausted — never auto-selected at boot/session start. */
  async function resolveLocalFallbackProvider(fetchImpl = apiFetchImpl) {
    let localTest;
    try {
      localTest = await testLocalLlmConnection(apiFetchImpl);
    } catch (err) {
      localTest = {
        ok: false,
        message: err instanceof Error ? err.message : String(err),
      };
    }
    if (!localTest.ok) {
      return {
        ok: false,
        message: localTest.message ?? '本地 LLM 不可用',
      };
    }
    const providerId = await ensureLocalFallbackProviderOnGoosed(
      apiTarget,
      apiSecret,
      fetchImpl,
    );
    return {
      ok: true,
      providerId,
      model: LOCAL_LLM_FALLBACK.model,
      source: 'local_fallback',
    };
  }

  const goosedApi = (pathname, init) => goosedApiFetch(apiTarget, apiSecret, pathname, init, apiFetchImpl);

  return {
    catalog: LLM_PROVIDER_CATALOG,

    async listKeys() {
      const [rows] = await pool.query(
        'SELECT * FROM h5_llm_provider_keys ORDER BY is_selected DESC, updated_at DESC',
      );
      return rows.map((row) =>
        rowToPublic(row, catalogItem(row.provider_id), decryptRow(row)),
      );
    },

    async createKey(payload) {
      const custom = isCustomPayload(payload);
      let providerKind = 'builtin';
      let providerId = String(payload?.providerId ?? '').trim();
      let insertName = String(payload?.name ?? '').trim();
      let apiKey = String(payload?.apiKey ?? '').trim();
      let defaultModel = String(payload?.defaultModel ?? '').trim();
      let apiUrl = null;
      let basePath = null;
      let engine = 'openai';
      let relayProvider = null;
      let modelsJson = null;
      let meta = catalogItem(providerId);

      if (custom) {
        const validated = validateCustomPayload(payload);
        if (!validated.ok) return validated;
        providerKind = 'custom';
        providerId = CUSTOM_PROVIDER_ID;
        meta = catalogById[CUSTOM_PROVIDER_ID];
        insertName = validated.value.name;
        apiKey = validated.value.apiKey;
        apiUrl = validated.value.apiUrl;
        basePath = validated.value.basePath;
        engine = validated.value.engine;
        relayProvider = validated.value.relayProvider;
        defaultModel = validated.value.defaultModel;
        modelsJson = JSON.stringify(validated.value.models);
      } else {
        if (!meta) return { ok: false, message: '不支持的 provider' };
        if (!insertName) return { ok: false, message: '请填写配置名称' };
        if (!apiKey) return { ok: false, message: '请填写 API Key' };
        defaultModel = defaultModel || meta.defaultModel;
        if (!meta.models.includes(defaultModel)) {
          return { ok: false, message: '不支持的模型' };
        }
      }

      const [existing] = await pool.query(
        'SELECT id FROM h5_llm_provider_keys WHERE name = ? LIMIT 1',
        [insertName],
      );
      if (existing.length > 0) return { ok: false, message: '配置名称已存在' };

      const [countRows] = await pool.query('SELECT COUNT(*) AS total FROM h5_llm_provider_keys');
      const shouldSelect = Number(countRows[0]?.total ?? 0) === 0;
      const encrypted = encryptSecret(apiKey, encryptionKey);
      const now = Date.now();
      const id = crypto.randomUUID();
      if (shouldSelect) await clearSelected();

      await pool.query(
        `INSERT INTO h5_llm_provider_keys
         (id, provider_id, provider_kind, api_url, base_path, models_json, goosed_provider_id, engine, relay_provider,
          name, api_key_ciphertext, api_key_iv, api_key_tag, default_model, status, is_selected, created_at, updated_at)
         VALUES (?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, 'active', ?, ?, ?)`,
        [
          id,
          providerId,
          providerKind,
          apiUrl,
          basePath,
          modelsJson,
          engine,
          relayProvider,
          insertName,
          encrypted.ciphertext,
          encrypted.iv,
          encrypted.tag,
          defaultModel,
          shouldSelect ? 1 : 0,
          now,
          now,
        ],
      );

      let row = await getRowById(id);
      if (shouldSelect) {
        await syncRow(row);
        row = await getRowById(id);
      }

      return { ok: true, key: rowToPublic(row, meta, apiKey) };
    },

    async updateKey(id, payload) {
      const row = await getRowById(id);
      if (!row) return { ok: false, message: '配置不存在' };
      const providerKind = row.provider_kind ?? 'builtin';

      const nextName =
        payload?.name !== undefined ? String(payload.name).trim() : row.name;
      const nextApiKey =
        payload?.apiKey !== undefined ? String(payload.apiKey).trim() : null;
      const nextStatus =
        payload?.status === 'disabled' || payload?.status === 'active'
          ? payload.status
          : row.status;

      if (!nextName) return { ok: false, message: '请填写配置名称' };

      const [existing] = await pool.query(
        'SELECT id FROM h5_llm_provider_keys WHERE name = ? AND id <> ? LIMIT 1',
        [nextName, id],
      );
      if (existing.length > 0) return { ok: false, message: '配置名称已存在' };

      if (row.is_selected && nextStatus === 'disabled') {
        return { ok: false, message: '当前启用的配置不能禁用，请先切换到其他配置' };
      }

      let nextModel = row.default_model;
      let nextApiUrl = row.api_url;
      let nextBasePath = row.base_path;
      let nextEngine = row.engine ?? 'openai';
      let nextRelayProvider = row.relay_provider;
      let nextModelsJson = row.models_json;

      if (providerKind === 'custom') {
        const models = payload?.models !== undefined
          ? parseModelList(payload.models)
          : parseModelsJson(row.models_json);
        nextModel =
          payload?.defaultModel !== undefined
            ? String(payload.defaultModel).trim()
            : row.default_model;
        nextApiUrl =
          payload?.apiUrl !== undefined
            ? normalizeApiUrl(payload.apiUrl)
            : row.api_url;
        nextBasePath =
          payload?.basePath !== undefined
            ? String(payload.basePath).trim() || null
            : row.base_path;
        nextEngine =
          payload?.engine !== undefined
            ? String(payload.engine).trim() || 'openai'
            : row.engine;
        nextRelayProvider =
          payload?.relayProvider !== undefined
            ? String(payload.relayProvider).trim() || null
            : row.relay_provider;
        if (models.length === 0) return { ok: false, message: '请至少保留一个模型' };
        if (!models.includes(nextModel)) {
          return { ok: false, message: '默认模型必须在模型列表中' };
        }
        if (!nextApiUrl) return { ok: false, message: '请填写 API 地址' };
        nextModelsJson = JSON.stringify(models);
      } else {
        const meta = catalogItem(row.provider_id);
        if (!meta) return { ok: false, message: '不支持的 provider' };
        nextModel =
          payload?.defaultModel !== undefined
            ? String(payload.defaultModel).trim()
            : row.default_model;
        if (!meta.models.includes(nextModel)) {
          return { ok: false, message: '不支持的模型' };
        }
      }

      const encrypted = nextApiKey
        ? encryptSecret(nextApiKey, encryptionKey)
        : {
            ciphertext: row.api_key_ciphertext,
            iv: row.api_key_iv,
            tag: row.api_key_tag,
          };

      const now = Date.now();
      await pool.query(
        `UPDATE h5_llm_provider_keys
         SET name = ?, api_url = ?, base_path = ?, models_json = ?, engine = ?, relay_provider = ?,
             api_key_ciphertext = ?, api_key_iv = ?, api_key_tag = ?,
             default_model = ?, status = ?, updated_at = ?
         WHERE id = ?`,
        [
          nextName,
          nextApiUrl,
          nextBasePath,
          nextModelsJson,
          nextEngine,
          nextRelayProvider,
          encrypted.ciphertext,
          encrypted.iv,
          encrypted.tag,
          nextModel,
          nextStatus,
          now,
          id,
        ],
      );

      if (row.is_selected) {
        await syncRow(await getRowById(id));
      }

      const updated = await getRowById(id);
      return {
        ok: true,
        key: rowToPublic(updated, catalogItem(updated.provider_id), nextApiKey || decryptRow(row)),
      };
    },

    async selectKey(id) {
      const row = await getRowById(id);
      if (!row) return { ok: false, message: '配置不存在' };
      if (row.status !== 'active') {
        return { ok: false, message: '已禁用的配置不能启用' };
      }
      await clearSelected();
      const now = Date.now();
      await pool.query(
        'UPDATE h5_llm_provider_keys SET is_selected = 1, updated_at = ? WHERE id = ?',
        [now, id],
      );
      await syncRow(row);
      const updated = await getRowById(id);
      return {
        ok: true,
        key: rowToPublic(updated, catalogItem(updated.provider_id), decryptRow(updated)),
      };
    },

    async deleteKey(id) {
      const row = await getRowById(id);
      if (!row) return { ok: false, message: '配置不存在' };
      if (row.is_selected) {
        return { ok: false, message: '当前启用的配置不能删除，请先切换到其他配置' };
      }
      if ((row.provider_kind ?? 'builtin') === 'custom' && row.goosed_provider_id) {
        await removeCustomProviderOnGoosed(
          apiTarget,
          apiSecret,
          row.goosed_provider_id,
          apiFetchImpl,
        );
      }
      await pool.query('DELETE FROM h5_llm_provider_keys WHERE id = ?', [id]);
      return { ok: true };
    },

    async syncSelectedToGoosed() {
      const resolved = await resolveSelectedProvider();
      if (!resolved.ok) {
        return { ok: false, synced: false, message: resolved.message };
      }
      return {
        ok: true,
        synced: true,
        source: resolved.source,
        providerId: resolved.providerId,
        model: resolved.model,
      };
    },

    async applyBestProviderForSession(sessionId, fetchImpl = apiFetchImpl) {
      const resolved = await resolveSelectedProvider(fetchImpl);
      if (!resolved.ok) {
        return resolved;
      }
      const sessionGoosedApi = (pathname, init) =>
        goosedApiFetch(apiTarget, apiSecret, pathname, init, fetchImpl);
      await updateSessionProvider(sessionGoosedApi, sessionId, resolved.providerId, resolved.model);
      return resolved;
    },

    /** Switch session to local Ollama (credits exhausted or relay 500 payload limit). */
    async applyLocalFallbackForSession(sessionId, fetchImpl = apiFetchImpl) {
      const resolved = await resolveLocalFallbackProvider(fetchImpl);
      if (!resolved.ok) {
        return resolved;
      }
      const sessionGoosedApi = (pathname, init) =>
        goosedApiFetch(apiTarget, apiSecret, pathname, init, fetchImpl);
      await updateSessionProvider(sessionGoosedApi, sessionId, resolved.providerId, resolved.model);
      return resolved;
    },

    async getGlobalSettings() {
      const row = await getSelectedRow();
      if (!row) {
        return {
          keyId: null,
          keyName: null,
          providerLabel: null,
          globalModel: null,
          availableModels: [],
        };
      }
      const publicRow = rowToPublic(row, catalogItem(row.provider_id), decryptRow(row));
      return {
        keyId: publicRow.id,
        keyName: publicRow.name,
        providerLabel: publicRow.providerLabel,
        globalModel: publicRow.defaultModel,
        availableModels: publicRow.models,
      };
    },

    async setGlobalModel(model) {
      const nextModel = String(model ?? '').trim();
      if (!nextModel) return { ok: false, message: '请选择全局模型' };
      const row = await getSelectedRow();
      if (!row) return { ok: false, message: '请先启用一个 LLM 配置' };

      const publicRow = rowToPublic(row, catalogItem(row.provider_id), decryptRow(row));
      if (!publicRow.models.includes(nextModel)) {
        return { ok: false, message: '模型不在当前 Provider 支持列表中' };
      }

      await pool.query(
        'UPDATE h5_llm_provider_keys SET default_model = ?, updated_at = ? WHERE id = ?',
        [nextModel, Date.now(), row.id],
      );
      await syncRow(await getRowById(row.id));
      return { ok: true, global: await this.getGlobalSettings() };
    },

    async testDraft(payload) {
      const custom = isCustomPayload(payload);
      if (!custom) {
        return { ok: false, message: '联通测试目前支持自定义 OpenAI 兼容配置' };
      }
      const validated = validateCustomPayload(payload);
      if (!validated.ok) return validated;
      const model = String(payload?.testModel ?? payload?.defaultModel ?? validated.value.defaultModel).trim();
      if (!validated.value.models.includes(model)) {
        return { ok: false, message: '测试模型不在模型列表中' };
      }
      return testRelayConnection(
        {
          apiUrl: validated.value.apiUrl,
          apiKey: validated.value.apiKey,
          model,
          relayProvider: validated.value.relayProvider,
        },
        apiFetchImpl,
      );
    },

    async testKey(id, testModel) {
      const row = await getRowById(id);
      if (!row) return { ok: false, message: '配置不存在' };
      if ((row.provider_kind ?? 'builtin') !== 'custom') {
        return { ok: false, message: '内置 Provider 联通测试暂未开放' };
      }
      const model = String(testModel ?? row.default_model).trim();
      const models = parseModelsJson(row.models_json);
      if (!models.includes(model)) {
        return { ok: false, message: '测试模型不在配置列表中' };
      }
      return testRelayConnection(
        {
          apiUrl: row.api_url,
          apiKey: decryptRow(row),
          model,
          relayProvider: row.relay_provider,
        },
        apiFetchImpl,
      );
    },

    async ensureBootstrapRelay() {
      const [existing] = await pool.query(
        'SELECT id FROM h5_llm_provider_keys WHERE name = ? LIMIT 1',
        [RELAY_BOOTSTRAP.name],
      );
      if (existing.length > 0) {
        const row = await getRowById(existing[0].id);
        if (row && !row.is_selected) {
          await this.selectKey(row.id);
        }
        return { ok: true, created: false, keyId: existing[0].id };
      }

      const result = await this.createKey({
        providerId: CUSTOM_PROVIDER_ID,
        name: RELAY_BOOTSTRAP.name,
        apiKey: RELAY_BOOTSTRAP.apiKey,
        apiUrl: RELAY_BOOTSTRAP.apiUrl,
        models: RELAY_BOOTSTRAP.models,
        defaultModel: RELAY_BOOTSTRAP.defaultModel,
        relayProvider: RELAY_BOOTSTRAP.relayProvider,
      });
      if (!result.ok) return result;
      if (result.key && !result.key.isSelected) {
        await this.selectKey(result.key.id);
      }
      return { ok: true, created: true, key: result.key };
    },
  };
}
