"use client";

import {
  Brain,
  CheckCircle2,
  ChevronLeft,
  ChevronRight,
  Copy,
  Eye,
  EyeOff,
  HelpCircle,
  Loader2,
  MoreHorizontal,
  Pencil,
  Plug,
  Plus,
  Search,
  Trash2,
  XCircle,
} from "lucide-react";

import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { Input } from "@/components/ui/input";
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from "@/components/ui/popover";
import { useCallback, useEffect, useState, type ReactNode } from "react";
import {
  credentialsApi,
  type Credential,
  type InterfaceType,
  type ModelType,
} from "@/lib/api";

/** 各资源类型可选的接口类型 */
const interfaceOptionsByType: Record<ModelType, InterfaceType[]> = {
  LLM: ["openai"],
  ASR: ["openai", "xfyun", "dashscope"],
  TTS: ["openai", "xfyun", "dashscope"],
  Realtime: ["openai", "gemini"],
  Embedding: ["openai"],
};

const modelTypes: ModelType[] = ["LLM", "ASR", "TTS", "Realtime", "Embedding"];

// 列表项类型直接复用 API 契约(camelCase,api_key 已打码)
type ModelResource = Credential;

type ModelForm = {
  name: string;
  modelId: string;
  type: ModelType;
  interfaceType: InterfaceType;
  apiUrl: string;
  apiKey: string;
  voice: string;
  speed: number;
  language: string;
};

const emptyForm: ModelForm = {
  name: "",
  modelId: "",
  type: "LLM",
  interfaceType: "openai",
  apiUrl: "",
  apiKey: "",
  voice: "",
  speed: 1,
  language: "",
};

type TypeFilter = "全部" | ModelType;

const typeFilters: TypeFilter[] = ["全部", ...modelTypes];

export function ComponentsModelsPage() {
  const [searchQuery, setSearchQuery] = useState("");
  const [typeFilter, setTypeFilter] = useState<TypeFilter>("全部");
  const [currentPage, setCurrentPage] = useState(1);

  const [models, setModels] = useState<ModelResource[]>([]);
  const [loading, setLoading] = useState(true);
  const [loadError, setLoadError] = useState<string | null>(null);

  const [dialogOpen, setDialogOpen] = useState(false);
  const [editingId, setEditingId] = useState<string | null>(null);
  // 编辑时记住原记录,保存时回填 isDefault 等未在表单暴露的字段
  const [editingModel, setEditingModel] = useState<ModelResource | null>(null);
  const [form, setForm] = useState<ModelForm>(emptyForm);
  const [showKey, setShowKey] = useState(false);
  const [saving, setSaving] = useState(false);
  const [saveError, setSaveError] = useState<string | null>(null);
  const [deletingId, setDeletingId] = useState<string | null>(null);
  const [duplicatingId, setDuplicatingId] = useState<string | null>(null);

  const [testing, setTesting] = useState(false);
  const [testResult, setTestResult] = useState<"idle" | "ok" | "fail">("idle");
  const [testMessage, setTestMessage] = useState("");

  const loadModels = useCallback(async () => {
    setLoading(true);
    setLoadError(null);
    try {
      setModels(await credentialsApi.list());
    } catch (error) {
      setLoadError(error instanceof Error ? error.message : "加载失败");
    } finally {
      setLoading(false);
    }
  }, []);

  useEffect(() => {
    // 挂载时拉取列表:这是与后端(外部系统)的同步,loadModels 内的 setLoading 属预期
    // eslint-disable-next-line react-hooks/set-state-in-effect
    void loadModels();
  }, [loadModels]);

  function updateForm<K extends keyof ModelForm>(key: K, value: ModelForm[K]) {
    setForm((prev) => ({ ...prev, [key]: value }));
    // 任何配置变更后，旧的测试结果不再可信，重置为待测状态
    setTestResult("idle");
    setTestMessage("");
  }

  async function handleTestConnection() {
    setTesting(true);
    setTestResult("idle");
    setTestMessage("");
    try {
      const result = await credentialsApi.test(
        {
          modelId: form.modelId.trim(),
          type: form.type,
          interfaceType: form.interfaceType,
          apiUrl: form.apiUrl.trim(),
          apiKey: form.apiKey,
          voice: form.voice.trim(),
          speed: form.speed,
          language: form.language.trim(),
        },
        editingId ?? undefined,
      );
      setTestResult(result.ok ? "ok" : "fail");
      setTestMessage(
        [
          result.message,
          result.latencyMs !== null ? `${result.latencyMs}ms` : "",
          result.detail,
        ]
          .filter(Boolean)
          .join(" · "),
      );
    } catch (error) {
      setTestResult("fail");
      setTestMessage(error instanceof Error ? error.message : "测试连接失败");
    } finally {
      setTesting(false);
    }
  }

  function handleTypeChange(type: ModelType) {
    const options = interfaceOptionsByType[type];
    setForm((prev) => ({
      ...prev,
      type,
      // 资源类型变化时，若当前接口类型不在新类型的可选项内则重置为首项
      interfaceType: options.includes(prev.interfaceType)
        ? prev.interfaceType
        : options[0],
      voice: type === "TTS" ? prev.voice : "",
      speed: type === "TTS" ? prev.speed : 1,
      language: type === "ASR" ? prev.language : "",
    }));
    setTestResult("idle");
    setTestMessage("");
  }

  function openCreate() {
    setEditingId(null);
    setEditingModel(null);
    setForm(emptyForm);
    setShowKey(false);
    setTestResult("idle");
    setTestMessage("");
    setSaveError(null);
    setDialogOpen(true);
  }

  function openEdit(model: ModelResource) {
    setEditingId(model.id);
    setEditingModel(model);
    setForm({
      name: model.name,
      modelId: model.modelId,
      type: model.type,
      interfaceType: model.interfaceType,
      apiUrl: model.apiUrl,
      // 编辑时不把打码占位符放入输入框；空值写回后端表示保留旧 key
      apiKey: "",
      voice: model.voice,
      speed: model.speed,
      language: model.language,
    });
    setShowKey(false);
    setTestResult("idle");
    setTestMessage("");
    setSaveError(null);
    setDialogOpen(true);
  }

  async function handleSave() {
    setSaving(true);
    setSaveError(null);
    const payload = {
      name: form.name.trim(),
      modelId: form.modelId.trim(),
      type: form.type,
      interfaceType: form.interfaceType,
      apiUrl: form.apiUrl.trim(),
      apiKey: form.apiKey,
      voice: form.voice.trim(),
      speed: form.speed,
      language: form.language.trim(),
      // 表单未暴露 isDefault,编辑时沿用原值,新建默认 false
      isDefault: editingModel?.isDefault ?? false,
    };
    try {
      if (editingId) {
        await credentialsApi.update(editingId, payload);
      } else {
        await credentialsApi.create(payload);
      }
      setDialogOpen(false);
      await loadModels();
    } catch (error) {
      setSaveError(error instanceof Error ? error.message : "保存失败");
    } finally {
      setSaving(false);
    }
  }

  async function handleDelete(id: string) {
    setDeletingId(id);
    try {
      await credentialsApi.remove(id);
      await loadModels();
    } catch (error) {
      setLoadError(error instanceof Error ? error.message : "删除失败");
    } finally {
      setDeletingId(null);
    }
  }

  // 服务端整行复制(含真 key,密钥不经浏览器)
  async function handleDuplicate(id: string) {
    setDuplicatingId(id);
    try {
      await credentialsApi.duplicate(id);
      await loadModels();
    } catch (error) {
      setLoadError(error instanceof Error ? error.message : "复制失败");
    } finally {
      setDuplicatingId(null);
    }
  }

  const filteredModels = models.filter((model) => {
    if (typeFilter !== "全部" && model.type !== typeFilter) {
      return false;
    }

    const keyword = searchQuery.trim().toLowerCase();
    if (!keyword) {
      return true;
    }

    return [model.name, model.modelId, model.type, model.interfaceType, model.apiUrl]
      .join(" ")
      .toLowerCase()
      .includes(keyword);
  });

  const pageSize = 5;
  const totalPages = Math.max(1, Math.ceil(filteredModels.length / pageSize));
  const safeCurrentPage = Math.min(currentPage, totalPages);
  const pageStart = (safeCurrentPage - 1) * pageSize;
  const pageEnd = pageStart + pageSize;
  const paginatedModels = filteredModels.slice(pageStart, pageEnd);

  function handleSearchChange(value: string) {
    setSearchQuery(value);
    setCurrentPage(1);
  }

  function handleFilterChange(filter: TypeFilter) {
    setTypeFilter(filter);
    setCurrentPage(1);
  }

  const interfaceOptions = interfaceOptionsByType[form.type];
  const hasStoredApiKey = Boolean(editingId && editingModel?.apiKey);
  const hasRequiredTypeOptions =
    form.type !== "TTS" || Boolean(form.voice.trim() && form.speed > 0);
  const canSave =
    form.name.trim() &&
    form.modelId.trim() &&
    form.apiUrl.trim() &&
    hasRequiredTypeOptions;
  const canTest = Boolean(
    form.modelId.trim() &&
      form.apiUrl.trim() &&
      hasRequiredTypeOptions &&
      (form.apiKey.trim() || editingModel?.apiKey),
  );

  return (
    <div className="mx-auto flex w-full max-w-[1440px] flex-col gap-8">
      <div className="flex flex-col items-start justify-between gap-5 sm:flex-row sm:gap-6">
        <div>
          <h1 className="font-display display-lg text-ink">模型资源</h1>
          <p className="mt-3 max-w-2xl text-[15px] leading-7 text-muted-foreground">
            统一管理 LLM、ASR、TTS、Realtime 与 Embedding 模型，配置各自的接口类型与访问凭证。
          </p>
        </div>

        <Button
          size="lg"
          className="w-full shrink-0 gap-2 sm:w-auto"
          onClick={openCreate}
        >
          <Plus size={16} />
          添加模型
        </Button>
      </div>

      <section className="rounded-2xl border border-hairline bg-card p-6 shadow-sm">
        <div className="mb-6 flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between">
          <div className="flex flex-wrap items-center gap-2">
            {typeFilters.map((filter) => (
              <Button
                key={filter}
                variant={filter === typeFilter ? "default" : "outline"}
                size="sm"
                className={
                  filter === typeFilter
                    ? "rounded-full"
                    : "rounded-full border-hairline-strong text-muted-foreground hover:text-foreground"
                }
                onClick={() => handleFilterChange(filter)}
              >
                {filter}
              </Button>
            ))}
          </div>

          <div className="relative w-full lg:w-[320px]">
            <Search
              size={15}
              className="pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-muted-soft"
            />
            <Input
              value={searchQuery}
              onChange={(event) => handleSearchChange(event.target.value)}
              className="h-10 border-hairline-strong bg-background pl-9 text-sm text-foreground placeholder:text-muted-soft"
              placeholder="搜索模型名称、接口类型或 URL..."
            />
          </div>
        </div>

        <div className="overflow-hidden rounded-xl border border-hairline">
          <div className="hidden items-center gap-4 bg-surface-strong/60 px-5 py-3 md:flex">
            <div className="caption-label flex-1 text-muted-soft">模型名称</div>
            <div className="caption-label w-[110px] text-muted-soft">
              资源类型
            </div>
            <div className="caption-label w-[110px] text-muted-soft">
              接口类型
            </div>
            <div className="caption-label w-[260px] text-muted-soft">
              API URL
            </div>
            <div className="caption-label w-[116px] text-right text-muted-soft">
              操作
            </div>
          </div>

          <div className="divide-y divide-hairline">
            {paginatedModels.map((model) => (
              <div
                key={model.id}
                className="flex flex-col gap-3 px-5 py-4 text-sm transition-colors hover:bg-surface-strong/40 md:flex-row md:items-center md:gap-4"
              >
                <div className="min-w-0 flex-1">
                  <div className="truncate font-medium text-foreground">
                    {model.name}
                  </div>
                  <div className="mt-1 text-xs text-muted-soft">
                    {model.modelId}
                  </div>
                </div>

                <div className="md:w-[110px]">
                  <Badge
                    variant="secondary"
                    className="h-6 bg-surface-strong px-3 text-muted-foreground"
                  >
                    {model.type}
                  </Badge>
                </div>

                <div className="md:w-[110px]">
                  <Badge
                    variant="secondary"
                    className="h-6 bg-surface-strong px-3 text-muted-foreground"
                  >
                    {model.interfaceType}
                  </Badge>
                </div>

                <div className="truncate text-muted-foreground md:w-[260px]">
                  {model.apiUrl}
                </div>

                <div className="flex justify-end gap-2 md:w-[116px]">
                  <Button
                    variant="outline"
                    size="sm"
                    className="gap-1.5 border-hairline-strong text-xs text-muted-foreground hover:text-foreground"
                    onClick={() => openEdit(model)}
                  >
                    <Pencil size={14} />
                    编辑
                  </Button>

                  <DropdownMenu>
                    <DropdownMenuTrigger asChild>
                      <Button
                        variant="outline"
                        size="icon-sm"
                        className="border-hairline-strong text-muted-foreground hover:text-foreground"
                        aria-label={`${model.name} 更多操作`}
                      >
                        <MoreHorizontal size={15} />
                      </Button>
                    </DropdownMenuTrigger>
                    <DropdownMenuContent
                      align="end"
                      className="w-32 min-w-32 rounded-xl border border-hairline bg-popover p-1"
                    >
                      <DropdownMenuItem
                        className="rounded-lg"
                        disabled={duplicatingId === model.id}
                        onSelect={(event) => {
                          event.preventDefault();
                          void handleDuplicate(model.id);
                        }}
                      >
                        {duplicatingId === model.id ? (
                          <Loader2 size={14} className="animate-spin" />
                        ) : (
                          <Copy size={14} />
                        )}
                        复制
                      </DropdownMenuItem>
                      <DropdownMenuItem
                        variant="destructive"
                        className="rounded-lg"
                        disabled={deletingId === model.id}
                        onSelect={(event) => {
                          event.preventDefault();
                          void handleDelete(model.id);
                        }}
                      >
                        {deletingId === model.id ? (
                          <Loader2 size={14} className="animate-spin" />
                        ) : (
                          <Trash2 size={14} />
                        )}
                        删除
                      </DropdownMenuItem>
                    </DropdownMenuContent>
                  </DropdownMenu>
                </div>
              </div>
            ))}

            {loading && (
              <div className="flex items-center justify-center gap-2 px-5 py-12 text-sm text-muted-foreground">
                <Loader2 size={16} className="animate-spin" />
                正在加载模型列表…
              </div>
            )}

            {!loading && loadError && (
              <div className="px-5 py-12 text-center">
                <div className="font-medium text-destructive">
                  加载失败
                </div>
                <div className="mt-2 text-sm text-muted-foreground">
                  {loadError}
                </div>
                <Button
                  variant="outline"
                  size="sm"
                  className="mt-4 border-hairline-strong text-muted-foreground hover:text-foreground"
                  onClick={() => void loadModels()}
                >
                  重试
                </Button>
              </div>
            )}

            {!loading && !loadError && filteredModels.length === 0 && (
              <div className="px-5 py-12 text-center">
                <div className="font-medium text-foreground">
                  {models.length === 0 ? "暂无模型资源" : "未找到匹配的模型"}
                </div>
                <div className="mt-2 text-sm text-muted-foreground">
                  {models.length === 0
                    ? "点击右上角「添加模型」创建第一个资源。"
                    : "请调整关键词或筛选条件后再试。"}
                </div>
              </div>
            )}
          </div>
        </div>

        <div className="mt-5 flex flex-col gap-3 text-sm text-muted-foreground sm:flex-row sm:items-center sm:justify-between">
          <div>
            {filteredModels.length === 0
              ? "没有数据"
              : `显示 ${pageStart + 1}-${Math.min(pageEnd, filteredModels.length)} / 共 ${filteredModels.length} 个模型`}
          </div>

          <div className="flex items-center gap-2">
            <Button
              variant="outline"
              size="icon-sm"
              className="border-hairline-strong text-muted-foreground hover:text-foreground"
              disabled={safeCurrentPage <= 1}
              onClick={() => setCurrentPage((page) => Math.max(1, page - 1))}
              aria-label="上一页"
            >
              <ChevronLeft size={15} />
            </Button>

            {Array.from({ length: totalPages }, (_, index) => index + 1).map(
              (page) => (
                <Button
                  key={page}
                  variant={page === safeCurrentPage ? "default" : "outline"}
                  size="sm"
                  className={[
                    "h-8 min-w-8 px-2",
                    page === safeCurrentPage
                      ? ""
                      : "border-hairline-strong text-muted-foreground hover:text-foreground",
                  ].join(" ")}
                  onClick={() => setCurrentPage(page)}
                >
                  {page}
                </Button>
              ),
            )}

            <Button
              variant="outline"
              size="icon-sm"
              className="border-hairline-strong text-muted-foreground hover:text-foreground"
              disabled={safeCurrentPage >= totalPages}
              onClick={() =>
                setCurrentPage((page) => Math.min(totalPages, page + 1))
              }
              aria-label="下一页"
            >
              <ChevronRight size={15} />
            </Button>
          </div>
        </div>
      </section>

      <Dialog open={dialogOpen} onOpenChange={setDialogOpen}>
        <DialogContent className="max-h-[calc(100vh-3rem)] overflow-y-auto sm:max-w-2xl">
          <DialogHeader>
            <DialogTitle>{editingId ? "编辑模型" : "添加模型"}</DialogTitle>
            <DialogDescription>
              填写资源名称、模型 ID、资源类型、接口类型与访问凭证。
            </DialogDescription>
          </DialogHeader>

          <div className="space-y-5">
            <div className="block">
              <FieldLabel
                htmlFor="model-name"
                hint={{
                  description:
                    "在控制台中展示的资源别名，便于识别和管理，可与模型 ID 不同。",
                  example: "DeepSeek-V3、Qwen-Max",
                }}
              >
                资源名称
              </FieldLabel>
              <Input
                id="model-name"
                value={form.name}
                autoFocus
                onChange={(event) => updateForm("name", event.target.value)}
                placeholder="请输入资源名称"
                className="border-hairline-strong bg-background text-foreground placeholder:text-muted-soft"
              />
            </div>

            <div className="block">
              <FieldLabel
                htmlFor="model-id"
                hint={{
                  description:
                    "调用 API 时传入的模型标识，需与服务商文档中的名称完全一致。",
                  example: "deepseek-chat、qwen-max、paraformer-realtime-v2",
                }}
              >
                模型 ID
              </FieldLabel>
              <Input
                id="model-id"
                value={form.modelId}
                onChange={(event) =>
                  updateForm("modelId", event.target.value)
                }
                placeholder="例如 deepseek-chat"
                className="border-hairline-strong bg-background text-foreground placeholder:text-muted-soft"
              />
            </div>

            <div className="grid grid-cols-1 gap-5 sm:grid-cols-2">
              <div className="block">
                <FieldLabel
                  hint={{
                    description:
                      "模型在语音管线中的能力分类，决定可选的接口类型与后续编排用途。",
                    example: "LLM、ASR、TTS、Realtime、Embedding",
                  }}
                >
                  资源类型
                </FieldLabel>
                <Select
                  value={form.type}
                  onValueChange={(value) => handleTypeChange(value as ModelType)}
                >
                  <SelectTrigger className="w-full border-hairline-strong bg-background text-foreground">
                    <SelectValue placeholder="请选择资源类型" />
                  </SelectTrigger>
                  <SelectContent className="border-hairline bg-popover text-popover-foreground">
                    {modelTypes.map((type) => (
                      <SelectItem key={type} value={type}>
                        {type}
                      </SelectItem>
                    ))}
                  </SelectContent>
                </Select>
              </div>

              <div className="block">
                <FieldLabel
                  hint={{
                    description:
                      "服务商 API 的协议或适配器类型，需与所选资源类型匹配。",
                    example: "openai、xfyun、dashscope、gemini",
                  }}
                >
                  接口类型
                </FieldLabel>
                <Select
                  value={form.interfaceType}
                  onValueChange={(value) =>
                    updateForm("interfaceType", value as InterfaceType)
                  }
                >
                  <SelectTrigger className="w-full border-hairline-strong bg-background text-foreground">
                    <SelectValue placeholder="请选择接口类型" />
                  </SelectTrigger>
                  <SelectContent className="border-hairline bg-popover text-popover-foreground">
                    {interfaceOptions.map((item) => (
                      <SelectItem key={item} value={item}>
                        {item}
                      </SelectItem>
                    ))}
                  </SelectContent>
                </Select>
              </div>
            </div>

            <div className="block">
              <FieldLabel
                htmlFor="model-api-url"
                hint={{
                  description:
                    "模型服务的 Base URL 或接口根地址，通常以 /v1 结尾，不含具体路径参数。",
                  example: "https://api.deepseek.com/v1",
                }}
              >
                API URL
              </FieldLabel>
              <Input
                id="model-api-url"
                value={form.apiUrl}
                onChange={(event) => updateForm("apiUrl", event.target.value)}
                placeholder="https://api.example.com/v1"
                className="border-hairline-strong bg-background text-foreground placeholder:text-muted-soft"
              />
            </div>

            {form.type === "TTS" && (
              <div className="grid grid-cols-1 gap-5 sm:grid-cols-2">
                <div className="block">
                  <FieldLabel
                    htmlFor="model-voice"
                    hint={{
                      description:
                        "调用语音合成接口时使用的音色标识，需与服务商支持的 voice 一致。",
                      example: "alloy、中文女",
                    }}
                  >
                    Voice
                  </FieldLabel>
                  <Input
                    id="model-voice"
                    value={form.voice}
                    onChange={(event) => updateForm("voice", event.target.value)}
                    placeholder="例如 alloy"
                    className="border-hairline-strong bg-background text-foreground placeholder:text-muted-soft"
                  />
                </div>
                <div className="block">
                  <FieldLabel
                    htmlFor="model-speed"
                    hint={{
                      description: "语音合成的播放速度，1 表示正常速度。",
                      example: "0.8、1、1.2",
                    }}
                  >
                    Speed
                  </FieldLabel>
                  <Input
                    id="model-speed"
                    type="number"
                    min="0.25"
                    max="4"
                    step="0.1"
                    value={form.speed}
                    onChange={(event) =>
                      updateForm("speed", Number(event.target.value) || 1)
                    }
                    className="border-hairline-strong bg-background text-foreground"
                  />
                </div>
              </div>
            )}

            {form.type === "ASR" && (
              <div className="block">
                <FieldLabel
                  htmlFor="model-language"
                  hint={{
                    description:
                      "语音识别的语言代码，留空时由模型自动判断或使用服务商默认值。",
                    example: "zh、en",
                  }}
                >
                  Language
                </FieldLabel>
                <Input
                  id="model-language"
                  value={form.language}
                  onChange={(event) => updateForm("language", event.target.value)}
                  placeholder="例如 zh，留空则自动识别"
                  className="border-hairline-strong bg-background text-foreground placeholder:text-muted-soft"
                />
              </div>
            )}

            <div className="block">
              <FieldLabel
                htmlFor="model-api-key"
                hint={{
                  description:
                    "访问模型服务的鉴权密钥，由服务商控制台生成，请妥善保管勿泄露。",
                  example: "sk-xxxxxxxx",
                }}
              >
                API Key
              </FieldLabel>
              {hasStoredApiKey && (
                <div className="mb-2 flex items-center gap-2 text-xs text-muted-foreground">
                  <span>当前密钥</span>
                  <code className="rounded-md bg-surface-strong px-2 py-1 font-mono text-foreground">
                    {editingModel?.apiKey}
                  </code>
                </div>
              )}
              <div className="relative">
                <Input
                  id="model-api-key"
                  value={form.apiKey}
                  type={showKey ? "text" : "password"}
                  onChange={(event) => updateForm("apiKey", event.target.value)}
                  placeholder={
                    hasStoredApiKey
                      ? "已配置，留空则保持不变"
                      : "请输入 API Key"
                  }
                  autoComplete="new-password"
                  className="border-hairline-strong bg-background pr-10 text-foreground placeholder:text-muted-soft"
                />
                <button
                  type="button"
                  onClick={() => setShowKey((value) => !value)}
                  disabled={!form.apiKey}
                  className="absolute right-3 top-1/2 -translate-y-1/2 text-muted-soft transition-colors hover:text-foreground disabled:cursor-not-allowed disabled:opacity-40"
                  aria-label={showKey ? "隐藏 API Key" : "显示 API Key"}
                >
                  {showKey ? <EyeOff size={16} /> : <Eye size={16} />}
                </button>
              </div>
              {hasStoredApiKey && (
                <p className="mt-2 text-xs leading-5 text-muted-foreground">
                  仅显示当前密钥首尾用于识别。留空可保持原密钥，输入新值将覆盖原密钥。
                </p>
              )}
            </div>
          </div>

          <DialogFooter className="sm:items-center sm:justify-between">
            <div className="flex items-center gap-3">
              <Button
                variant="outline"
                size="sm"
                className="gap-2 border-hairline-strong text-muted-foreground hover:text-foreground"
                disabled={!canTest || testing}
                onClick={handleTestConnection}
              >
                {testing ? (
                  <Loader2 size={14} className="animate-spin" />
                ) : (
                  <Plug size={14} />
                )}
                测试连接
              </Button>
              {testResult === "ok" && (
                <span className="flex items-center gap-1.5 text-xs text-emerald-500">
                  <CheckCircle2 size={14} />
                  {testMessage}
                </span>
              )}
              {testResult === "fail" && (
                <span className="flex items-center gap-1.5 text-xs text-destructive">
                  <XCircle size={14} />
                  {testMessage}
                </span>
              )}
              {saveError && (
                <span className="flex items-center gap-1.5 text-xs text-destructive">
                  <XCircle size={14} />
                  {saveError}
                </span>
              )}
            </div>

            <div className="flex items-center gap-2">
              <Button
                variant="outline"
                className="border-hairline-strong text-muted-foreground hover:text-foreground"
                disabled={saving}
                onClick={() => setDialogOpen(false)}
              >
                取消
              </Button>
              <Button
                className="gap-2"
                disabled={!canSave || saving}
                onClick={() => void handleSave()}
              >
                {saving ? (
                  <Loader2 size={16} className="animate-spin" />
                ) : (
                  <Brain size={16} />
                )}
                {editingId ? "保存" : "添加"}
              </Button>
            </div>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </div>
  );
}

function FieldLabel({
  htmlFor,
  children,
  hint,
}: {
  htmlFor?: string;
  children: ReactNode;
  hint: { description: string; example?: string };
}) {
  return (
    <div className="mb-2 flex items-center gap-1.5 text-sm font-medium text-foreground">
      <label htmlFor={htmlFor}>{children}</label>
      <HelpHint {...hint} />
    </div>
  );
}

function HelpHint({
  description,
  example,
}: {
  description: string;
  example?: string;
}) {
  return (
    <Popover>
      <PopoverTrigger asChild>
        <button
          type="button"
          aria-label="查看说明"
          className="flex h-5 w-5 items-center justify-center rounded-full text-muted-soft transition-colors hover:bg-surface-strong hover:text-foreground"
        >
          <HelpCircle size={14} />
        </button>
      </PopoverTrigger>
      <PopoverContent
        align="start"
        className="w-72 space-y-2 text-sm leading-6 text-muted-foreground"
      >
        <p>{description}</p>
        {example && (
          <p className="text-xs leading-5 text-muted-soft">
            <span className="font-medium text-muted-foreground">填写样例：</span>
            {example}
          </p>
        )}
      </PopoverContent>
    </Popover>
  );
}
