"use client";

import {
  Bot,
  Boxes,
  Brain,
  Check,
  Copy,
  Database,
  Eye,
  EyeOff,
  MessageSquareText,
  MoreHorizontal,
  Pencil,
  Plus,
  Rocket,
  Search,
  Sparkles,
  Trash2,
  Workflow,
  ChevronLeft,
  ChevronRight,
  Save,
  Mic,
  Send,
  HelpCircle,
  Waypoints,
  AudioLines,
  Terminal,
  Loader2,
  PhoneOff,
  Orbit,
  Waves,
} from "lucide-react";

import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { Input } from "@/components/ui/input";
import { Textarea } from "@/components/ui/textarea";
import { Switch } from "@/components/ui/switch";
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from "@/components/ui/popover";
import { AuraVisualizer } from "@/components/ui/aura-visualizer";
import { SpectrumVisualizer } from "@/components/ui/spectrum-visualizer";
import { WaveVisualizer } from "@/components/ui/wave-visualizer";
import {
  Card,
  CardContent,
  CardHeader,
  CardTitle,
} from "@/components/ui/card";
import { useCallback, useEffect, useRef, useState } from "react";
import {
  assistantsApi,
  credentialsApi,
  knowledgeBasesApi,
  type Assistant,
  type AssistantType as ApiAssistantType,
  type AssistantUpsert,
  type Credential,
  type KnowledgeBase,
} from "@/lib/api";

type RuntimeMode = "pipeline" | "realtime";

type AssistantForm = {
  name: string;
  greeting: string;
  prompt: string;
  runtimeMode: RuntimeMode;
  realtimeModel: string;
  model: string;
  asr: string;
  voice: string;
  knowledgeBase: string;
  enableInterrupt: boolean;
};

type FastGptForm = {
  name: string;
  appId: string;
  apiUrl: string;
  apiKey: string;
  asr: string;
  voice: string;
  enableInterrupt: boolean;
};

type DifyForm = {
  name: string;
  apiUrl: string;
  apiKey: string;
  asr: string;
  voice: string;
  enableInterrupt: boolean;
};

type OpenCodeForm = {
  name: string;
  prompt: string;
  apiUrl: string;
  apiKey: string;
  model: string;
  asr: string;
  voice: string;
  enableInterrupt: boolean;
};

type AssistantType = "提示词" | "工作流" | "Dify" | "FastGPT" | "OpenCode";

const assistantTypes: AssistantType[] = [
  "提示词",
  "工作流",
  "Dify",
  "FastGPT",
  "OpenCode",
];

// 后端 type(英文) ↔ 列表展示标签(中文)
const typeToLabel: Record<ApiAssistantType, AssistantType> = {
  prompt: "提示词",
  workflow: "工作流",
  dify: "Dify",
  fastgpt: "FastGPT",
  opencode: "OpenCode",
};
function formatTimestamp(iso?: string | null): string {
  if (!iso) return "";
  const d = new Date(iso);
  if (Number.isNaN(d.getTime())) return "";
  const pad = (n: number) => String(n).padStart(2, "0");
  return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(
    d.getHours(),
  )}:${pad(d.getMinutes())}`;
}

type AssistantTypeOption = {
  type: AssistantType;
  label: string;
  description: string;
  icon: React.ReactNode;
  /** 提示词、Dify、FastGPT 类型已落地，工作流暂时显示占位页 */
  available: boolean;
};

const assistantTypeOptions: AssistantTypeOption[] = [
  {
    type: "提示词",
    label: "使用提示词构建",
    description: "通过提示词、模型与语音快速搭建对话助手，适合大多数场景。",
    icon: <MessageSquareText size={20} />,
    available: true,
  },
  {
    type: "工作流",
    label: "使用工作流构建",
    description: "用可视化编排串联多个节点，适合多步骤、带分支的复杂流程。",
    icon: <Workflow size={20} />,
    available: false,
  },
  {
    type: "Dify",
    label: "使用 Dify 构建",
    description: "对接 Dify 应用，复用其编排能力与知识库配置。",
    icon: <Boxes size={20} />,
    available: true,
  },
  {
    type: "FastGPT",
    label: "使用 FastGPT 构建",
    description: "对接 FastGPT 应用，复用其知识库问答与工作流能力。",
    icon: <Database size={20} />,
    available: true,
  },
  {
    type: "OpenCode",
    label: "使用 OpenCode 构建",
    description: "对接 OpenCode 服务，通过提示词驱动代码助手并支持实时语音对话。",
    icon: <Terminal size={20} />,
    available: true,
  },
];

type AssistantListItem = {
  id: string;
  name: string;
  type: AssistantType;
  updatedAt: string;
};

type TypeFilter = "全部" | AssistantType;

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

export function AssistantPage() {
  const [form, setForm] = useState<AssistantForm>({
    name: "政务视频咨询助手",
    greeting: "您好，我是 AI 视频助手，请问有什么可以帮您？",
    prompt:
      "你是一名专业的政务视频咨询助手，负责为市民提供政策解读、办事指南和常见问题解答。\n\n请遵循以下原则：\n1. 回答准确、简洁，使用通俗易懂的语言\n2. 不确定的信息应明确告知，不编造政策内容\n3. 涉及具体办事流程时，引导用户前往官方渠道核实",
    runtimeMode: "pipeline",
    realtimeModel: "",
    model: "",
    asr: "",
    voice: "",
    knowledgeBase: "",
    enableInterrupt: true,
  });
  const [fastGptForm, setFastGptForm] = useState<FastGptForm>({
    name: "FastGPT 售后咨询助手",
    appId: "",
    apiUrl: "https://api.fastgpt.in/api/v1/chat/completions",
    apiKey: "",
    asr: "",
    voice: "",
    enableInterrupt: true,
  });
  const [difyForm, setDifyForm] = useState<DifyForm>({
    name: "Dify 知识库问答助手",
    apiUrl: "https://api.dify.ai/v1/chat-messages",
    apiKey: "",
    asr: "",
    voice: "",
    enableInterrupt: true,
  });
  const [openCodeForm, setOpenCodeForm] = useState<OpenCodeForm>({
    name: "OpenCode 代码助手",
    prompt:
      "你是一个代码助手的语音交互界面，请用简洁、口语化的方式回答用户关于代码与工程的问题。",
    apiUrl: "http://localhost:4096",
    apiKey: "",
    model: "",
    asr: "",
    voice: "",
    enableInterrupt: true,
  });
  const [assistants, setAssistants] = useState<Assistant[]>([]);
  const [listLoading, setListLoading] = useState(true);
  const [listError, setListError] = useState<string | null>(null);
  // 编辑中的助手 id;null = 新建
  const [editingId, setEditingId] = useState<string | null>(null);
  const [saving, setSaving] = useState(false);
  const [saveError, setSaveError] = useState<string | null>(null);
  // 下拉数据源:模型凭证 + 知识库
  const [credentials, setCredentials] = useState<Credential[]>([]);
  const [knowledgeBases, setKnowledgeBases] = useState<KnowledgeBase[]>([]);
  const [view, setView] = useState<
    | "list"
    | "choose"
    | "create"
    | "create-dify"
    | "create-fastgpt"
    | "create-opencode"
    | "placeholder"
  >("list");
  const [searchQuery, setSearchQuery] = useState("");
  const [typeFilter, setTypeFilter] = useState<TypeFilter>("全部");
  const [currentPage, setCurrentPage] = useState(1);
  // choose 步骤的草稿：名称与已选类型，确认后才决定进入哪个构建页
  const [draftName, setDraftName] = useState("");
  const [draftType, setDraftType] = useState<AssistantType | null>(null);

  const loadAssistants = useCallback(async () => {
    setListLoading(true);
    setListError(null);
    try {
      setAssistants(await assistantsApi.list());
    } catch (error) {
      setListError(error instanceof Error ? error.message : "加载失败");
    } finally {
      setListLoading(false);
    }
  }, []);

  useEffect(() => {
    // 挂载时拉取助手列表(与后端同步)
    // eslint-disable-next-line react-hooks/set-state-in-effect
    void loadAssistants();
  }, [loadAssistants]);

  // 进入创建/编辑前加载下拉数据源(模型凭证 + 知识库)
  const loadResources = useCallback(async () => {
    try {
      const [creds, kbs] = await Promise.all([
        credentialsApi.list(),
        knowledgeBasesApi.list(),
      ]);
      setCredentials(creds);
      setKnowledgeBases(kbs);
    } catch {
      // 拉取失败时下拉为空,不阻塞表单
    }
  }, []);

  // 按资源类型生成 {value:id, label:name} 选项
  const credOptions = (type: Credential["type"]) =>
    credentials
      .filter((c) => c.type === type)
      .map((c) => ({ value: c.id, label: c.name }));
  const kbOptions = knowledgeBases.map((k) => ({ value: k.id, label: k.name }));

  function startCreate() {
    setDraftName("");
    setDraftType(null);
    setView("choose");
  }

  // 提示词类型的空白模板(新建用)
  function blankPromptForm(name: string): AssistantForm {
    return {
      name,
      greeting: "",
      prompt: "",
      runtimeMode: "pipeline",
      realtimeModel: "",
      model: "",
      asr: "",
      voice: "",
      knowledgeBase: "",
      enableInterrupt: true,
    };
  }

  // 把后端 Assistant 回填进提示词表单(注意:model/asr/voice 等存的是凭证 id)
  function fillPromptForm(a: Assistant) {
    setForm({
      name: a.name,
      greeting: a.greeting,
      prompt: a.prompt,
      runtimeMode: a.runtimeMode,
      realtimeModel: a.realtimeCredentialId ?? "",
      model: a.llmCredentialId ?? "",
      asr: a.asrCredentialId ?? "",
      voice: a.ttsCredentialId ?? "",
      knowledgeBase: a.knowledgeBaseId ?? "",
      enableInterrupt: a.enableInterrupt,
    });
  }

  // 编辑：根据助手类型进入对应的构建/编辑页
  async function handleEdit(assistant: AssistantListItem) {
    if (assistant.type === "提示词") {
      void loadResources();
      setSaveError(null);
      setEditingId(assistant.id);
      try {
        fillPromptForm(await assistantsApi.get(assistant.id));
        setView("create");
      } catch (error) {
        setListError(error instanceof Error ? error.message : "加载助手失败");
      }
    } else if (assistant.type === "FastGPT") {
      void loadResources();
      setSaveError(null);
      setEditingId(assistant.id);
      try {
        fillFastGptForm(await assistantsApi.get(assistant.id));
        setView("create-fastgpt");
      } catch (error) {
        setListError(error instanceof Error ? error.message : "加载助手失败");
      }
    } else if (assistant.type === "Dify") {
      void loadResources();
      setSaveError(null);
      setEditingId(assistant.id);
      try {
        fillDifyForm(await assistantsApi.get(assistant.id));
        setView("create-dify");
      } catch (error) {
        setListError(error instanceof Error ? error.message : "加载助手失败");
      }
    } else if (assistant.type === "OpenCode") {
      void loadResources();
      setSaveError(null);
      setEditingId(assistant.id);
      try {
        fillOpenCodeForm(await assistantsApi.get(assistant.id));
        setView("create-opencode");
      } catch (error) {
        setListError(error instanceof Error ? error.message : "加载助手失败");
      }
    } else {
      // 工作流：暂时显示占位页
      setDraftName(assistant.name);
      setDraftType(assistant.type);
      setView("placeholder");
    }
  }

  function confirmType() {
    if (!draftName.trim() || !draftType) {
      return;
    }

    if (draftType === "提示词") {
      // 提示词类型：新建,空白模板 + 带入名称
      void loadResources();
      setEditingId(null);
      setSaveError(null);
      setForm(blankPromptForm(draftName.trim()));
      setView("create");
    } else if (draftType === "FastGPT") {
      // FastGPT 类型：新建,清空表单 + 带入名称
      void loadResources();
      setEditingId(null);
      setSaveError(null);
      setFastGptForm({
        name: draftName.trim(),
        appId: "",
        apiUrl: "",
        apiKey: "",
        model: "",
        asr: "",
        voice: "",
        enableInterrupt: true,
      });
      setView("create-fastgpt");
    } else if (draftType === "Dify") {
      // Dify 类型：新建,清空表单 + 带入名称
      void loadResources();
      setEditingId(null);
      setSaveError(null);
      setDifyForm({
        name: draftName.trim(),
        apiUrl: "",
        apiKey: "",
        asr: "",
        voice: "",
        enableInterrupt: true,
      });
      setView("create-dify");
    } else if (draftType === "OpenCode") {
      // OpenCode 类型：新建,清空表单 + 带入名称
      void loadResources();
      setEditingId(null);
      setSaveError(null);
      setOpenCodeForm({
        name: draftName.trim(),
        prompt: "",
        apiUrl: "",
        apiKey: "",
        asr: "",
        voice: "",
        enableInterrupt: true,
      });
      setView("create-opencode");
    } else {
      // 工作流：暂时显示占位页
      setView("placeholder");
    }
  }

  // 复制助手：服务端整行复制(含真 key,密钥不经浏览器)
  async function handleDuplicate(assistant: AssistantListItem) {
    try {
      await assistantsApi.duplicate(assistant.id);
      await loadAssistants();
    } catch (error) {
      setListError(error instanceof Error ? error.message : "复制失败");
    }
  }

  // 删除助手
  async function handleDelete(id: string) {
    try {
      await assistantsApi.remove(id);
      await loadAssistants();
    } catch (error) {
      setListError(error instanceof Error ? error.message : "删除失败");
    }
  }

  // 平铺字段的空白 upsert,各类型按需覆盖(后端会按 type 清掉无关字段)
  function baseUpsert(over: Partial<AssistantUpsert>): AssistantUpsert {
    return {
      name: "",
      type: "prompt",
      runtimeMode: "pipeline",
      greeting: "",
      enableInterrupt: true,
      llmCredentialId: null,
      asrCredentialId: null,
      ttsCredentialId: null,
      realtimeCredentialId: null,
      knowledgeBaseId: null,
      prompt: "",
      apiUrl: "",
      apiKey: "",
      appId: "",
      graph: {},
      ...over,
    };
  }

  // 统一的保存:新建 POST / 编辑 PUT
  async function save(payload: AssistantUpsert) {
    setSaving(true);
    setSaveError(null);
    try {
      if (editingId) await assistantsApi.update(editingId, payload);
      else await assistantsApi.create(payload);
      await loadAssistants();
      setView("list");
    } catch (error) {
      setSaveError(error instanceof Error ? error.message : "保存失败");
    } finally {
      setSaving(false);
    }
  }

  function handleSavePrompt() {
    void save(
      baseUpsert({
        name: form.name.trim(),
        type: "prompt",
        runtimeMode: form.runtimeMode,
        greeting: form.greeting,
        enableInterrupt: form.enableInterrupt,
        llmCredentialId: form.model || null,
        asrCredentialId: form.asr || null,
        ttsCredentialId: form.voice || null,
        realtimeCredentialId: form.realtimeModel || null,
        knowledgeBaseId: form.knowledgeBase || null,
        prompt: form.prompt,
      }),
    );
  }

  // ---- Dify ----
  function fillDifyForm(a: Assistant) {
    setDifyForm({
      name: a.name,
      apiUrl: a.apiUrl,
      // 编辑时不把打码占位符放入输入框；空值写回后端表示保留旧 key
      apiKey: "",
      model: a.llmCredentialId ?? "",
      asr: a.asrCredentialId ?? "",
      voice: a.ttsCredentialId ?? "",
      enableInterrupt: a.enableInterrupt,
    });
  }

  function handleSaveDify() {
    void save(
      baseUpsert({
        name: difyForm.name.trim(),
        type: "dify",
        enableInterrupt: difyForm.enableInterrupt,
        asrCredentialId: difyForm.asr || null,
        ttsCredentialId: difyForm.voice || null,
        apiUrl: difyForm.apiUrl,
        apiKey: difyForm.apiKey,
      }),
    );
  }

  // ---- FastGPT ----
  function fillFastGptForm(a: Assistant) {
    setFastGptForm({
      name: a.name,
      appId: a.appId,
      apiUrl: a.apiUrl,
      // 编辑时不把打码占位符放入输入框；空值写回后端表示保留旧 key
      apiKey: "",
      asr: a.asrCredentialId ?? "",
      voice: a.ttsCredentialId ?? "",
      enableInterrupt: a.enableInterrupt,
    });
  }

  function handleSaveFastGpt() {
    void save(
      baseUpsert({
        name: fastGptForm.name.trim(),
        type: "fastgpt",
        enableInterrupt: fastGptForm.enableInterrupt,
        asrCredentialId: fastGptForm.asr || null,
        ttsCredentialId: fastGptForm.voice || null,
        appId: fastGptForm.appId,
        apiUrl: fastGptForm.apiUrl,
        apiKey: fastGptForm.apiKey,
      }),
    );
  }

  // ---- OpenCode ----
  function fillOpenCodeForm(a: Assistant) {
    setOpenCodeForm({
      name: a.name,
      prompt: a.prompt,
      apiUrl: a.apiUrl,
      // 编辑时不把打码占位符放入输入框；空值写回后端表示保留旧 key
      apiKey: "",
      asr: a.asrCredentialId ?? "",
      voice: a.ttsCredentialId ?? "",
      enableInterrupt: a.enableInterrupt,
    });
  }

  function handleSaveOpenCode() {
    void save(
      baseUpsert({
        name: openCodeForm.name.trim(),
        type: "opencode",
        enableInterrupt: openCodeForm.enableInterrupt,
        llmCredentialId: openCodeForm.model || null,
        asrCredentialId: openCodeForm.asr || null,
        ttsCredentialId: openCodeForm.voice || null,
        prompt: openCodeForm.prompt,
        apiUrl: openCodeForm.apiUrl,
        apiKey: openCodeForm.apiKey,
      }),
    );
  }

  const listItems: AssistantListItem[] = assistants.map((a) => ({
    id: a.id,
    name: a.name,
    type: typeToLabel[a.type],
    updatedAt: formatTimestamp(a.updatedAt),
  }));
  const storedApiKeyMask =
    (editingId &&
      assistants.find((assistant) => assistant.id === editingId)?.apiKey) ||
    "";

  const filteredAssistants = listItems.filter((assistant) => {
    if (typeFilter !== "全部" && assistant.type !== typeFilter) {
      return false;
    }

    const keyword = searchQuery.trim().toLowerCase();

    if (!keyword) {
      return true;
    }

    return [assistant.name, assistant.id, assistant.type, assistant.updatedAt]
      .join(" ")
      .toLowerCase()
      .includes(keyword);
  });

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

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

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

  function updateForm<K extends keyof AssistantForm>(
    key: K,
    value: AssistantForm[K],
  ) {
    setForm((prev) => ({
      ...prev,
      [key]: value,
    }));
  }

  function updateFastGptForm<K extends keyof FastGptForm>(
    key: K,
    value: FastGptForm[K],
  ) {
    setFastGptForm((prev) => ({
      ...prev,
      [key]: value,
    }));
  }

  function updateDifyForm<K extends keyof DifyForm>(
    key: K,
    value: DifyForm[K],
  ) {
    setDifyForm((prev) => ({
      ...prev,
      [key]: value,
    }));
  }

  function updateOpenCodeForm<K extends keyof OpenCodeForm>(
    key: K,
    value: OpenCodeForm[K],
  ) {
    setOpenCodeForm((prev) => ({
      ...prev,
      [key]: value,
    }));
  }
  if (view === "list") {
    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">
              管理已有的视频助手，支持提示词、工作流、Dify 和 FastGPT 类型。
            </p>
          </div>

          <Button
            size="lg"
            className="w-full shrink-0 gap-2 sm:w-auto"
            onClick={startCreate}
          >
            <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="搜索助手名称、类型或 ID..."
              />
            </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-[150px] text-muted-soft">
                更新时间
              </div>
              <div className="caption-label w-[116px] text-right text-muted-soft">
                操作
              </div>
            </div>

            <div className="divide-y divide-hairline">
              {paginatedAssistants.map((assistant) => (
                <div
                  key={assistant.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">
                      {assistant.name}
                    </div>
                    <div className="mt-1 text-xs text-muted-soft">
                      {assistant.id}
                    </div>
                  </div>

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

                  <div className="text-muted-foreground md:w-[150px]">
                    {assistant.updatedAt}
                  </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={() => handleEdit(assistant)}
                    >
                      <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={`${assistant.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"
                          onSelect={() => handleDuplicate(assistant)}
                        >
                          <Copy size={14} />
                          复制
                        </DropdownMenuItem>
                        <DropdownMenuItem
                          variant="destructive"
                          className="rounded-lg"
                          onSelect={(event) => {
                            event.preventDefault();
                            void handleDelete(assistant.id);
                          }}
                        >
                          <Trash2 size={14} />
                          删除
                        </DropdownMenuItem>
                      </DropdownMenuContent>
                    </DropdownMenu>
                  </div>
                </div>
              ))}

              {listLoading && (
                <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>
              )}

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

              {!listLoading && !listError && filteredAssistants.length === 0 && (
                <div className="px-5 py-12 text-center">
                  <div className="font-medium text-foreground">
                    {listItems.length === 0
                      ? "暂无助手"
                      : "未找到匹配的助手"}
                  </div>
                  <div className="mt-2 text-sm text-muted-foreground">
                    {listItems.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>
              {filteredAssistants.length === 0
                ? "没有数据"
                : `显示 ${pageStart + 1}-${Math.min(pageEnd, filteredAssistants.length)} / 共 ${filteredAssistants.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>
      </div>
    );
  }

  if (view === "choose") {
    const selectedOption = assistantTypeOptions.find(
      (option) => option.type === draftType,
    );

    return (
      <div className="mx-auto flex w-full max-w-[1180px] flex-col gap-8">
        <div className="flex items-start justify-between 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">
              先为助手取个名字，再选择构建方式。不同方式将进入不同的构建流程。
            </p>
          </div>

          <Button
            variant="outline"
            size="lg"
            className="shrink-0 gap-2 border-hairline-strong text-muted-foreground hover:text-foreground"
            onClick={() => setView("list")}
          >
            <ChevronLeft size={16} />
            返回列表
          </Button>
        </div>

        <section className="rounded-2xl border border-hairline bg-card p-6 shadow-sm">
          <label className="block">
            <div className="mb-2 text-sm font-medium text-foreground">
              助手名称
            </div>
            <Input
              value={draftName}
              autoFocus
              onChange={(event) => setDraftName(event.target.value)}
              placeholder="请输入助手名称"
              className="border-hairline-strong bg-background text-foreground placeholder:text-muted-soft"
            />
          </label>
        </section>

        <section className="flex flex-col gap-4">
          <div className="text-sm font-medium text-foreground">构建方式</div>

          <div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
            {assistantTypeOptions.map((option) => {
              const selected = draftType === option.type;

              return (
                <button
                  key={option.type}
                  type="button"
                  onClick={() => setDraftType(option.type)}
                  className={`group relative flex flex-col gap-4 rounded-2xl border bg-card p-5 text-left transition-colors ${
                    selected
                      ? "border-primary ring-1 ring-primary"
                      : "border-hairline hover:border-hairline-strong"
                  }`}
                >
                  <div className="flex items-center justify-between">
                    <div className="flex h-11 w-11 items-center justify-center rounded-full bg-surface-strong text-foreground">
                      {option.icon}
                    </div>

                    {selected ? (
                      <span className="flex h-6 w-6 items-center justify-center rounded-full bg-primary text-primary-foreground">
                        <Check size={14} />
                      </span>
                    ) : (
                      !option.available && (
                        <Badge
                          variant="secondary"
                          className="h-6 bg-surface-strong px-3 text-xs text-muted-foreground"
                        >
                          即将上线
                        </Badge>
                      )
                    )}
                  </div>

                  <div>
                    <div className="text-base font-medium text-foreground">
                      {option.label}
                    </div>
                    <p className="mt-1.5 text-sm leading-6 text-muted-foreground">
                      {option.description}
                    </p>
                  </div>
                </button>
              );
            })}
          </div>
        </section>

        <div className="flex items-center justify-end gap-3">
          <Button
            variant="outline"
            size="lg"
            className="border-hairline-strong text-muted-foreground hover:text-foreground"
            onClick={() => setView("list")}
          >
            取消
          </Button>
          <Button
            size="lg"
            className="gap-2"
            disabled={!draftName.trim() || !draftType}
            onClick={confirmType}
          >
            <Rocket size={16} />
            {selectedOption && !selectedOption.available
              ? "下一步"
              : "开始构建"}
          </Button>
        </div>
      </div>
    );
  }

  if (view === "placeholder") {
    return (
      <div className="mx-auto flex w-full max-w-[1180px] flex-col gap-6">
        <div className="flex items-start justify-between gap-6">
          <div>
            <h1 className="font-display display-lg text-ink">
              {draftName.trim() || "创建助手"}
            </h1>
            <p className="mt-3 max-w-2xl text-[15px] leading-7 text-muted-foreground">
              {draftType} 构建方式正在开发中，敬请期待。
            </p>
          </div>

          <Button
            variant="outline"
            size="lg"
            className="shrink-0 gap-2 border-hairline-strong text-muted-foreground hover:text-foreground"
            onClick={() => setView("list")}
          >
            <ChevronLeft size={16} />
            返回列表
          </Button>
        </div>

        <section className="relative overflow-hidden rounded-3xl border border-hairline bg-canvas-soft px-10 py-20 text-center">
          <div
            aria-hidden
            className="pointer-events-none absolute -right-24 top-0 h-72 w-72 rounded-full opacity-50 blur-3xl"
            style={{
              backgroundImage:
                "radial-gradient(circle, color-mix(in srgb, var(--gradient-sky) 50%, transparent), transparent 70%)",
            }}
          />
          <div
            aria-hidden
            className="pointer-events-none absolute -left-20 bottom-0 h-64 w-64 rounded-full opacity-45 blur-3xl"
            style={{
              backgroundImage:
                "radial-gradient(circle, color-mix(in srgb, var(--gradient-lavender) 50%, transparent), transparent 70%)",
            }}
          />
          <div className="relative">
            <div className="caption-label inline-flex rounded-full bg-surface-strong px-3 py-1 text-muted-foreground">
              建设中
            </div>
            <p className="font-display display-sm mx-auto mt-5 max-w-md text-ink">
              {draftType} 构建页面正在编写中
            </p>
            <p className="mx-auto mt-3 max-w-md text-sm leading-7 text-body">
              页面骨架与设计语言已就绪，后续将填充具体构建流程与数据。
            </p>
          </div>
        </section>
      </div>
    );
  }

  if (view === "create-dify") {
    return (
      <div className="-mt-6 flex h-full flex-col gap-4">
        <div className="flex shrink-0 items-center justify-between gap-6 border-b border-hairline pb-3 pt-1">
          <div className="flex min-w-0 items-center gap-2">
            <EditorBackButton onClick={() => setView("list")} />
            <EditableTitle
              value={difyForm.name}
              onChange={(value) => updateDifyForm("name", value)}
            />
          </div>

          <div className="flex shrink-0 gap-2">
            {saveError && (
              <span className="self-center text-xs text-destructive">
                {saveError}
              </span>
            )}
            <Button
              className="gap-2"
              disabled={saving || !difyForm.name.trim()}
              onClick={() => void handleSaveDify()}
            >
              {saving ? (
                <Loader2 size={16} className="animate-spin" />
              ) : (
                <Save size={16} />
              )}
              保存
            </Button>
          </div>
        </div>

        <div className="flex min-h-0 flex-1 gap-6">
          <div className="min-w-0 flex-1 space-y-5 overflow-y-auto pr-1">
            <SectionCard
              icon={<Boxes size={18} />}
              title="Dify 应用配置"
              description="填写 API URL 与 API Key 以对接 Dify 应用。开场白、知识库、提示词等对话编排请在 Dify 平台配置，本页不重复设置。"
            >
              <InputField
                label="API URL"
                value={difyForm.apiUrl}
                onChange={(value) => updateDifyForm("apiUrl", value)}
                placeholder="https://api.dify.ai/v1/chat-messages"
              />
              <SecretInputField
                label="API Key"
                value={difyForm.apiKey}
                onChange={(value) => updateDifyForm("apiKey", value)}
                placeholder="请输入 Dify API Key"
                storedValueMask={storedApiKeyMask}
              />
            </SectionCard>

            <SectionCard
              icon={<Brain size={18} />}
              title="语音配置"
              description="从「模型资源」中选择语音识别与语音合成。大模型、知识库与开场白由 Dify 应用提供，请前往 Dify 平台配置。"
            >
              <ResourceSelectField
                label="语音识别"
                value={difyForm.asr}
                onChange={(value) => updateDifyForm("asr", value)}
                options={credOptions("ASR")}
                noneLabel="无"
              />
              <ResourceSelectField
                label="语音合成"
                value={difyForm.voice}
                onChange={(value) => updateDifyForm("voice", value)}
                options={credOptions("TTS")}
                noneLabel="无"
              />
            </SectionCard>

            <SectionCard
              icon={<Sparkles size={18} />}
              title="交互策略"
              description="设置实时视频对话时的交互体验"
            >
              <ToggleRow
                title="允许用户打断"
                description="用户说话时，助手可以停止当前播报并重新理解用户输入"
                checked={difyForm.enableInterrupt}
                onChange={(checked) =>
                  updateDifyForm("enableInterrupt", checked)
                }
              />
            </SectionCard>
          </div>

          <DebugDrawer />
        </div>
      </div>
    );
  }

  if (view === "create-fastgpt") {
    return (
      <div className="-mt-6 flex h-full flex-col gap-4">
        <div className="flex shrink-0 items-center justify-between gap-6 border-b border-hairline pb-3 pt-1">
          <div className="flex min-w-0 items-center gap-2">
            <EditorBackButton onClick={() => setView("list")} />
            <EditableTitle
              value={fastGptForm.name}
              onChange={(value) => updateFastGptForm("name", value)}
            />
          </div>

          <div className="flex shrink-0 gap-2">
            {saveError && (
              <span className="self-center text-xs text-destructive">
                {saveError}
              </span>
            )}
            <Button
              className="gap-2"
              disabled={saving || !fastGptForm.name.trim()}
              onClick={() => void handleSaveFastGpt()}
            >
              {saving ? (
                <Loader2 size={16} className="animate-spin" />
              ) : (
                <Save size={16} />
              )}
              保存
            </Button>
          </div>
        </div>

        <div className="flex min-h-0 flex-1 gap-6">
          <div className="min-w-0 flex-1 space-y-5 overflow-y-auto pr-1">
            <SectionCard
              icon={<Database size={18} />}
              title="FastGPT 应用配置"
              description="填写 App ID、API URL 与 API Key 以对接 FastGPT 应用。开场白、知识库、提示词等对话编排请在 FastGPT 平台配置，本页不重复设置。"
            >
              <InputField
                label="App ID"
                value={fastGptForm.appId}
                onChange={(value) => updateFastGptForm("appId", value)}
                placeholder="请输入 FastGPT 应用 ID"
              />
              <InputField
                label="API URL"
                value={fastGptForm.apiUrl}
                onChange={(value) => updateFastGptForm("apiUrl", value)}
                placeholder="https://api.fastgpt.in/api/v1/chat/completions"
              />
              <SecretInputField
                label="API Key"
                value={fastGptForm.apiKey}
                onChange={(value) => updateFastGptForm("apiKey", value)}
                placeholder="请输入 FastGPT API Key"
                storedValueMask={storedApiKeyMask}
              />
            </SectionCard>

            <SectionCard
              icon={<Brain size={18} />}
              title="语音配置"
              description="从「模型资源」中选择语音识别与语音合成。大模型、知识库与开场白由 FastGPT 应用提供，请前往 FastGPT 平台配置。"
            >
              <ResourceSelectField
                label="语音识别"
                value={fastGptForm.asr}
                onChange={(value) => updateFastGptForm("asr", value)}
                options={credOptions("ASR")}
                noneLabel="无"
              />
              <ResourceSelectField
                label="语音合成"
                value={fastGptForm.voice}
                onChange={(value) => updateFastGptForm("voice", value)}
                options={credOptions("TTS")}
                noneLabel="无"
              />
            </SectionCard>

            <SectionCard
              icon={<Sparkles size={18} />}
              title="交互策略"
              description="设置实时视频对话时的交互体验"
            >
              <ToggleRow
                title="允许用户打断"
                description="用户说话时，助手可以停止当前播报并重新理解用户输入"
                checked={fastGptForm.enableInterrupt}
                onChange={(checked) =>
                  updateFastGptForm("enableInterrupt", checked)
                }
              />
            </SectionCard>
          </div>

          <DebugDrawer />
        </div>
      </div>
    );
  }

  if (view === "create-opencode") {
    return (
      <div className="-mt-6 flex h-full flex-col gap-4">
        <div className="flex shrink-0 items-center justify-between gap-6 border-b border-hairline pb-3 pt-1">
          <div className="flex min-w-0 items-center gap-2">
            <EditorBackButton onClick={() => setView("list")} />
            <EditableTitle
              value={openCodeForm.name}
              onChange={(value) => updateOpenCodeForm("name", value)}
            />
          </div>

          <div className="flex shrink-0 gap-2">
            {saveError && (
              <span className="self-center text-xs text-destructive">
                {saveError}
              </span>
            )}
            <Button
              className="gap-2"
              disabled={saving || !openCodeForm.name.trim()}
              onClick={() => void handleSaveOpenCode()}
            >
              {saving ? (
                <Loader2 size={16} className="animate-spin" />
              ) : (
                <Save size={16} />
              )}
              保存
            </Button>
          </div>
        </div>

        <div className="flex min-h-0 flex-1 gap-6">
          <div className="min-w-0 flex-1 space-y-5 overflow-y-auto pr-1">
            <SectionCard
              icon={<Terminal size={18} />}
              title="OpenCode 服务配置"
              description="填写 OpenCode 服务地址与 API Key 以对接代码助手。"
            >
              <InputField
                label="OpenCode URL"
                value={openCodeForm.apiUrl}
                onChange={(value) => updateOpenCodeForm("apiUrl", value)}
                placeholder="http://localhost:4096"
              />
              <SecretInputField
                label="API Key"
                value={openCodeForm.apiKey}
                onChange={(value) => updateOpenCodeForm("apiKey", value)}
                placeholder="请输入 OpenCode API Key"
                storedValueMask={storedApiKeyMask}
              />
            </SectionCard>

            <SectionCard
              icon={<MessageSquareText size={18} />}
              title="提示词"
              description="描述助手的角色、能力和回答要求"
            >
              <TextAreaField
                value={openCodeForm.prompt}
                onChange={(value) => updateOpenCodeForm("prompt", value)}
                placeholder="请输入提示词，描述助手的角色、能力和回答要求"
                rows={8}
              />
            </SectionCard>

            <SectionCard
              icon={<Brain size={18} />}
              title="模型与语音配置"
              description="配置 OpenCode 使用的大语言模型、语音识别与语音合成资源。"
            >
              <ResourceSelectField
                label="大语言模型"
                value={openCodeForm.model}
                onChange={(value) => updateOpenCodeForm("model", value)}
                options={credOptions("LLM")}
                noneLabel="无"
              />
              <ResourceSelectField
                label="语音识别"
                value={openCodeForm.asr}
                onChange={(value) => updateOpenCodeForm("asr", value)}
                options={credOptions("ASR")}
                noneLabel="无"
              />
              <ResourceSelectField
                label="语音合成"
                value={openCodeForm.voice}
                onChange={(value) => updateOpenCodeForm("voice", value)}
                options={credOptions("TTS")}
                noneLabel="无"
              />
            </SectionCard>

            <SectionCard
              icon={<Sparkles size={18} />}
              title="交互策略"
              description="设置实时视频对话时的交互体验"
            >
              <ToggleRow
                title="允许用户打断"
                description="用户说话时，助手可以停止当前播报并重新理解用户输入"
                checked={openCodeForm.enableInterrupt}
                onChange={(checked) =>
                  updateOpenCodeForm("enableInterrupt", checked)
                }
              />
            </SectionCard>
          </div>

          <DebugDrawer />
        </div>
      </div>
    );
  }

  return (
    <div className="-mt-6 flex h-full flex-col gap-4">
      <div className="flex shrink-0 items-center justify-between gap-6 border-b border-hairline pb-3 pt-1">
        <div className="flex min-w-0 items-center gap-2">
          <EditorBackButton onClick={() => setView("list")} />
          <EditableTitle
            value={form.name}
            onChange={(value) => updateForm("name", value)}
          />
        </div>

        <div className="flex shrink-0 gap-2">
          {saveError && (
            <span className="self-center text-xs text-destructive">
              {saveError}
            </span>
          )}
          <Button
            className="gap-2"
            disabled={saving || !form.name.trim()}
            onClick={() => void handleSavePrompt()}
          >
            {saving ? (
              <Loader2 size={16} className="animate-spin" />
            ) : (
              <Save size={16} />
            )}
            保存
          </Button>
        </div>
      </div>

      <div className="flex min-h-0 flex-1 gap-6">
        <div className="min-w-0 flex-1 space-y-5 overflow-y-auto pr-1">
          <SectionCard>
            <div className="grid grid-cols-1 gap-4 md:grid-cols-2">
              <div
                role="button"
                tabIndex={0}
                onClick={() => updateForm("runtimeMode", "pipeline")}
                onKeyDown={(event) => {
                  if (event.key === "Enter" || event.key === " ") {
                    event.preventDefault();
                    updateForm("runtimeMode", "pipeline");
                  }
                }}
                className={[
                  "cursor-pointer rounded-2xl border p-5 text-left transition-colors",
                  form.runtimeMode === "pipeline"
                    ? "border-primary bg-primary/5 ring-1 ring-primary"
                    : "border-hairline bg-canvas-soft hover:border-hairline-strong",
                ].join(" ")}
              >
                <div className="flex items-center justify-between gap-3">
                  <div className="flex items-center gap-3">
                    <div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-surface-strong text-foreground">
                      <Waypoints size={18} />
                    </div>
                    <div className="flex items-center gap-1.5">
                      <span className="font-medium text-foreground">Pipeline 模式</span>
                      <HelpHint text="通过 ASR、LLM 和 TTS 级联组成语音管线，灵活选配各模块。" />
                    </div>
                  </div>
                  {form.runtimeMode === "pipeline" && (
                    <span className="flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-primary text-primary-foreground">
                      <Check size={14} />
                    </span>
                  )}
                </div>
              </div>

              <div
                role="button"
                tabIndex={0}
                onClick={() => updateForm("runtimeMode", "realtime")}
                onKeyDown={(event) => {
                  if (event.key === "Enter" || event.key === " ") {
                    event.preventDefault();
                    updateForm("runtimeMode", "realtime");
                  }
                }}
                className={[
                  "cursor-pointer rounded-2xl border p-5 text-left transition-colors",
                  form.runtimeMode === "realtime"
                    ? "border-primary bg-primary/5 ring-1 ring-primary"
                    : "border-hairline bg-canvas-soft hover:border-hairline-strong",
                ].join(" ")}
              >
                <div className="flex items-center justify-between gap-3">
                  <div className="flex items-center gap-3">
                    <div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-surface-strong text-foreground">
                      <AudioLines size={18} />
                    </div>
                    <div className="flex items-center gap-1.5">
                      <span className="font-medium text-foreground">Realtime 模式</span>
                      <HelpHint text="使用原生实时语音模型，模型直接处理音频输入并生成语音回复。" />
                    </div>
                  </div>
                  {form.runtimeMode === "realtime" && (
                    <span className="flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-primary text-primary-foreground">
                      <Check size={14} />
                    </span>
                  )}
                </div>
              </div>
            </div>
          </SectionCard>

          <SectionCard
            icon={<MessageSquareText size={18} />}
            title="提示词"
            description="描述助手的角色、能力和回答要求"
          >
            <TextAreaField
              value={form.prompt}
              onChange={(value) => updateForm("prompt", value)}
              placeholder="请输入提示词，描述助手的角色、能力和回答要求"
              rows={8}
            />
          </SectionCard>

          {form.runtimeMode === "pipeline" ? (
            <SectionCard
              icon={<Brain size={18} />}
              title="模型配置"
              description="从「模型资源」中选择大语言模型、语音识别与语音合成"
            >
              <ResourceSelectField
                label="大语言模型"
                value={form.model}
                onChange={(value) => updateForm("model", value)}
                options={credOptions("LLM")}
                noneLabel="无"
              />
              <ResourceSelectField
                label="语音识别"
                value={form.asr}
                onChange={(value) => updateForm("asr", value)}
                options={credOptions("ASR")}
                noneLabel="无"
              />
              <ResourceSelectField
                label="语音合成"
                value={form.voice}
                onChange={(value) => updateForm("voice", value)}
                options={credOptions("TTS")}
                noneLabel="无"
              />
            </SectionCard>
          ) : (
            <SectionCard
              icon={<Brain size={18} />}
              title="模型配置"
              description="当前模式下 ASR 与 TTS 由 Realtime 模型内置完成"
            >
              <ResourceSelectField
                label="Realtime 模型"
                value={form.realtimeModel}
                onChange={(value) => updateForm("realtimeModel", value)}
                options={credOptions("Realtime")}
                noneLabel="无"
              />
            </SectionCard>
          )}

          <SectionCard
            icon={<Bot size={18} />}
            title="开场白"
            description="助手与用户首次对话时的开场语"
          >
            <TextAreaField
              value={form.greeting}
              onChange={(value) => updateForm("greeting", value)}
              placeholder="请输入助手开场白"
            />
          </SectionCard>

          <SectionCard
            icon={<Database size={18} />}
            title="知识库配置"
            description="选择助手回答时可检索的业务知识来源"
          >
            <ResourceSelectField
              value={form.knowledgeBase}
              onChange={(value) => updateForm("knowledgeBase", value)}
              options={kbOptions}
              noneLabel="无"
            />
          </SectionCard>

          <SectionCard
            icon={<Sparkles size={18} />}
            title="交互策略"
            description="设置实时视频对话时的交互体验"
          >
            <ToggleRow
              title="允许用户打断"
              description="用户说话时，助手可以停止当前播报并重新理解用户输入"
              checked={form.enableInterrupt}
              onChange={(checked) => updateForm("enableInterrupt", checked)}
            />
          </SectionCard>
        </div>

        <DebugDrawer />
      </div>
    </div>
  );
}

type VizStyle = "aura" | "bars" | "wave";

const VIZ_ORDER: VizStyle[] = ["aura", "bars", "wave"];
const VIZ_LABEL: Record<VizStyle, string> = {
  aura: "光环",
  bars: "频谱",
  wave: "波形",
};

function DebugDrawer() {
  const [showTranscript, setShowTranscript] = useState(false);
  const [vizStyle, setVizStyle] = useState<VizStyle>("wave");

  return (
    <aside className="hidden min-w-0 flex-1 flex-col overflow-hidden rounded-2xl border border-hairline bg-card shadow-sm lg:flex">
      <div className="flex shrink-0 items-center justify-between gap-3 border-b border-hairline px-5 py-4">
        <div className="text-sm font-medium text-foreground">调试与预览</div>
        <div className="flex items-center gap-2">
          {!showTranscript && (
            <Button
              type="button"
              variant="outline"
              size="icon"
              className="h-8 w-8 rounded-full"
              onClick={() =>
                setVizStyle(
                  (value) =>
                    VIZ_ORDER[
                      (VIZ_ORDER.indexOf(value) + 1) % VIZ_ORDER.length
                    ],
                )
              }
              aria-label={`切换可视化样式（当前：${VIZ_LABEL[vizStyle]}）`}
              title={`可视化：${VIZ_LABEL[vizStyle]}`}
            >
              {vizStyle === "aura" ? (
                <Orbit size={16} />
              ) : vizStyle === "bars" ? (
                <AudioLines size={16} />
              ) : (
                <Waves size={16} />
              )}
            </Button>
          )}
          <Button
            type="button"
            variant={showTranscript ? "default" : "outline"}
            size="icon"
            className="h-8 w-8 rounded-full text-xs font-medium"
            onClick={() => setShowTranscript((value) => !value)}
            aria-label={showTranscript ? "显示音频可视化" : "显示文字聊天记录"}
            aria-pressed={showTranscript}
          >
            文
          </Button>
        </div>
      </div>

      <DebugVoicePanel showTranscript={showTranscript} vizStyle={vizStyle} />
    </aside>
  );
}

function DebugVoicePanel({
  showTranscript,
  vizStyle,
}: {
  showTranscript: boolean;
  vizStyle: VizStyle;
}) {
  const [recording, setRecording] = useState(false);
  const [micError, setMicError] = useState(false);

  return (
    <div className="flex min-h-0 flex-1 flex-col">
      {showTranscript ? (
        <DebugTranscriptPanel />
      ) : (
        <div className="relative flex min-h-0 flex-1 flex-col items-center justify-center gap-3 overflow-y-auto px-6 py-3 text-center">
          <div
            className="pointer-events-none absolute left-1/2 top-2 h-72 w-72 -translate-x-1/2 rounded-full opacity-50 blur-3xl"
            style={{
              background:
                "radial-gradient(circle, color-mix(in srgb, var(--gradient-sky) 42%, transparent), color-mix(in srgb, var(--gradient-lavender) 18%, transparent) 48%, transparent 74%)",
            }}
          />

          <Badge
            variant="secondary"
            className="relative gap-1.5 rounded-full border border-hairline bg-canvas-soft px-3 py-1 text-[11px] font-medium text-muted-foreground shadow-none"
          >
            <span
              className={[
                "h-1.5 w-1.5 rounded-full",
                recording ? "animate-pulse bg-success" : "bg-muted-soft",
              ].join(" ")}
            />
            {recording ? "会话进行中" : "准备开始"}
          </Badge>

          <div className="relative flex h-[200px] w-[240px] shrink-0 items-center justify-center">
            {(() => {
              const onVizError = () => {
                setMicError(true);
                setRecording(false);
              };
              const shared = {
                active: recording,
                className: "relative shrink-0",
                onError: onVizError,
              } as const;
              if (vizStyle === "aura")
                return <AuraVisualizer {...shared} size={200} />;
              if (vizStyle === "bars")
                return (
                  <SpectrumVisualizer {...shared} size={200} barCount={64} />
                );
              return <WaveVisualizer {...shared} size={200} />;
            })()}
          </div>

          <div className="relative max-w-xs space-y-1.5">
            <div className="font-display display-sm text-foreground">
              {recording ? "我在聆听" : "开始一次语音对话"}
            </div>
            <p className="mx-auto text-xs leading-5 text-muted-foreground">
              {micError
                ? "无法访问麦克风，请检查浏览器权限后重试。"
                : recording
                  ? "直接说话即可。助手会在您停顿后自然回应。"
                  : "测试语音识别、响应速度与助手的播报效果。"}
            </p>
          </div>

          <Button
            onClick={() => {
              setMicError(false);
              setRecording((value) => !value);
            }}
            className={[
              "relative h-11 gap-2 rounded-full px-6 text-sm font-medium shadow-sm transition-transform hover:scale-[1.03]",
              recording
                ? "bg-destructive text-white hover:bg-destructive/90"
                : "",
            ].join(" ")}
            aria-label={recording ? "结束语音测试" : "开始语音测试"}
          >
            {recording ? <PhoneOff size={18} /> : <Mic size={18} />}
            {recording ? "结束对话" : "开始对话"}
          </Button>
        </div>
      )}

      <div className="shrink-0 border-t border-hairline bg-card p-3">
        <div className="flex items-end gap-2">
          <Textarea
            rows={1}
            placeholder="输入文字以模拟用户消息…"
            className="max-h-24 min-h-10 flex-1 resize-none border-hairline-strong bg-background text-sm text-foreground placeholder:text-muted-soft"
          />
          <Button size="icon" className="shrink-0" aria-label="发送调试消息">
            <Send size={16} />
          </Button>
        </div>
      </div>
    </div>
  );
}

function DebugTranscriptPanel() {
  return (
    <div className="flex min-h-0 flex-1 flex-col overflow-y-auto px-5 py-4">
      <div className="flex flex-col gap-4">
        <div className="flex max-w-[88%] flex-col gap-1 self-start">
          <span className="px-1 text-[11px] text-muted-soft">助手 · 10:24</span>
          <div className="rounded-2xl rounded-tl-sm bg-surface-strong px-4 py-2.5 text-sm leading-6 text-foreground">
            您好，我是 AI 视频助手，请问有什么可以帮您？
          </div>
        </div>

        <div className="flex max-w-[88%] flex-col items-end gap-1 self-end">
          <span className="px-1 text-[11px] text-muted-soft">我 · 10:25</span>
          <div className="rounded-2xl rounded-tr-sm bg-primary px-4 py-2.5 text-sm leading-6 text-primary-foreground">
            我想了解一下社保卡的办理流程。
          </div>
        </div>

        <div className="flex max-w-[88%] flex-col gap-1 self-start">
          <span className="px-1 text-[11px] text-muted-soft">助手 · 10:25</span>
          <div className="rounded-2xl rounded-tl-sm bg-surface-strong px-4 py-2.5 text-sm leading-6 text-foreground">
            社保卡可通过线上或线下渠道办理。线上可在政务服务 App
            提交申请，线下可前往社保经办网点。
          </div>
        </div>
      </div>
    </div>
  );
}

function EditorBackButton({ onClick }: { onClick: () => void }) {
  return (
    <Button
      variant="ghost"
      size="icon"
      className="shrink-0 text-muted-foreground hover:text-foreground"
      onClick={onClick}
      aria-label="返回助手列表"
    >
      <ChevronLeft size={20} />
    </Button>
  );
}

function EditableTitle({
  value,
  onChange,
}: {
  value: string;
  onChange: (value: string) => void;
}) {
  const [editing, setEditing] = useState(false);
  const [draft, setDraft] = useState(value);
  const inputRef = useRef<HTMLInputElement>(null);

  useEffect(() => {
    if (editing) {
      inputRef.current?.focus();
      inputRef.current?.select();
    }
  }, [editing]);

  function startEdit() {
    setDraft(value);
    setEditing(true);
  }

  function commit() {
    const next = draft.trim();
    if (next) {
      onChange(next);
    }
    setEditing(false);
  }

  if (editing) {
    return (
      <input
        ref={inputRef}
        value={draft}
        onChange={(event) => setDraft(event.target.value)}
        onBlur={commit}
        onKeyDown={(event) => {
          if (event.key === "Enter") {
            event.preventDefault();
            commit();
          } else if (event.key === "Escape") {
            event.preventDefault();
            setEditing(false);
          }
        }}
        className="font-display display-sm w-[min(60vw,420px)] border-b border-primary bg-transparent text-ink outline-none"
      />
    );
  }

  return (
    <button
      type="button"
      onClick={startEdit}
      title="点击修改助手名称"
      className="group -mx-2 flex min-w-0 items-center gap-2 rounded-lg px-2 py-1 text-left transition-colors hover:bg-surface-strong"
    >
      <span className="font-display display-sm truncate text-ink">
        {value || "未命名助手"}
      </span>
      <Pencil
        size={16}
        className="shrink-0 text-muted-soft opacity-0 transition-opacity group-hover:opacity-100"
      />
    </button>
  );
}

function HelpHint({ text }: { text: string }) {
  return (
    <Popover>
      <PopoverTrigger asChild>
        <button
          type="button"
          aria-label="查看说明"
          onClick={(event) => event.stopPropagation()}
          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 text-sm leading-6 text-muted-foreground"
      >
        {text}
      </PopoverContent>
    </Popover>
  );
}

function SectionCard({
  icon,
  title,
  description,
  children,
}: {
  icon?: React.ReactNode;
  title?: string;
  description?: string;
  children: React.ReactNode;
}) {
  const hasHeader = Boolean(title);

  return (
    <Card className="rounded-2xl border-hairline bg-card text-card-foreground shadow-sm">
      {hasHeader && (
        <CardHeader>
          <div className="flex items-center gap-3">
            {icon && (
              <div className="flex h-10 w-10 items-center justify-center rounded-full bg-surface-strong text-foreground">
                {icon}
              </div>
            )}

            <div className="flex items-center gap-1.5">
              <CardTitle className="text-base font-medium">{title}</CardTitle>
              {description && <HelpHint text={description} />}
            </div>
          </div>
        </CardHeader>
      )}

      <CardContent className={hasHeader ? "space-y-4" : undefined}>
        {children}
      </CardContent>
    </Card>
  );
}

function InputField({
  label,
  value,
  placeholder,
  type = "text",
  onChange,
}: {
  label?: string;
  value: string;
  placeholder?: string;
  type?: string;
  onChange: (value: string) => void;
}) {
  return (
    <label className="block">
      {label && (
        <div className="mb-2 text-sm font-medium text-foreground">{label}</div>
      )}
      <Input
        value={value}
        type={type}
        placeholder={placeholder}
        onChange={(event) => onChange(event.target.value)}
        className="border-hairline-strong bg-background text-foreground placeholder:text-muted-soft"
      />
    </label>
  );
}

function SecretInputField({
  label,
  value,
  placeholder,
  storedValueMask,
  onChange,
}: {
  label?: string;
  value: string;
  placeholder?: string;
  storedValueMask: string;
  onChange: (value: string) => void;
}) {
  const [showValue, setShowValue] = useState(false);
  const hasStoredValue = Boolean(storedValueMask);

  return (
    <label className="block">
      {label && (
        <div className="mb-2 text-sm font-medium text-foreground">{label}</div>
      )}
      {hasStoredValue && (
        <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">
            {storedValueMask}
          </code>
        </div>
      )}
      <div className="relative">
        <Input
          value={value}
          type={showValue ? "text" : "password"}
          placeholder={
            hasStoredValue ? "已配置，留空则保持不变" : placeholder
          }
          autoComplete="new-password"
          onChange={(event) => {
            const nextValue = event.target.value;
            if (!nextValue) setShowValue(false);
            onChange(nextValue);
          }}
          className="border-hairline-strong bg-background pr-10 text-foreground placeholder:text-muted-soft"
        />
        <button
          type="button"
          disabled={!value}
          onClick={() => setShowValue((current) => !current)}
          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={showValue ? "隐藏 API Key" : "显示 API Key"}
        >
          {showValue ? <EyeOff size={16} /> : <Eye size={16} />}
        </button>
      </div>
      {hasStoredValue && (
        <p className="mt-2 text-xs leading-5 text-muted-foreground">
          仅显示当前密钥首尾用于识别。留空可保持原密钥，输入新值将覆盖原密钥。
        </p>
      )}
    </label>
  );
}

function TextAreaField({
  label,
  value,
  placeholder,
  rows = 4,
  onChange,
}: {
  label?: string;
  value: string;
  placeholder?: string;
  rows?: number;
  onChange: (value: string) => void;
}) {
  return (
    <label className="block">
      {label && (
        <div className="mb-2 text-sm font-medium text-foreground">{label}</div>
      )}
      <Textarea
        value={value}
        placeholder={placeholder}
        onChange={(event) => onChange(event.target.value)}
        rows={rows}
        className="resize-none border-hairline-strong bg-background text-foreground placeholder:text-muted-soft"
      />
    </label>
  );
}

// Radix Select 不允许空字符串 value,用哨兵表示"未选/无"
const NONE_VALUE = "__none__";

function ResourceSelectField({
  label,
  value,
  options,
  noneLabel,
  onChange,
}: {
  label?: string;
  value: string;
  options: { value: string; label: string }[];
  /** 提供则在顶部加一个"无/默认"选项,选中映射为空串 */
  noneLabel?: string;
  onChange: (value: string) => void;
}) {
  return (
    <div className="block">
      {label && (
        <div className="mb-2 text-sm font-medium text-foreground">{label}</div>
      )}

      <Select
        value={value || NONE_VALUE}
        onValueChange={(v) => onChange(v === NONE_VALUE ? "" : v)}
      >
        <SelectTrigger className="w-full border-hairline-strong bg-background text-foreground">
          <SelectValue placeholder={label ? `请选择${label}` : "请选择"} />
        </SelectTrigger>

        <SelectContent className="border-hairline bg-popover text-popover-foreground">
          {noneLabel && (
            <SelectItem value={NONE_VALUE}>{noneLabel}</SelectItem>
          )}
          {options.map((item) => (
            <SelectItem key={item.value} value={item.value}>
              {item.label}
            </SelectItem>
          ))}
        </SelectContent>
      </Select>
    </div>
  );
}

function ToggleRow({
  title,
  description,
  checked,
  onChange,
}: {
  title: string;
  description: string;
  checked: boolean;
  onChange: (checked: boolean) => void;
}) {
  return (
    <div className="flex items-center justify-between rounded-xl border border-hairline bg-canvas-soft p-4">
      <div>
        <div className="font-medium text-foreground">{title}</div>
        <div className="mt-1 text-sm text-muted-foreground">{description}</div>
      </div>
      <Switch checked={checked} onCheckedChange={onChange} />
    </div>
  );
}
