import { useCallback, useEffect, useState } from "react";
import { Link } from "react-router-dom";
import * as settingsApi from "../api/settings";
import { useAvatars } from "../context/AvatarContext";
import { useBootstrap } from "../context/BootstrapContext";
import type { EnvironmentInfo, ExtensionInfo, McpServerInfo, SettingsPaneId, SkillInfo } from "../types/events";
import type { McpToolInfo } from "../types/events";
import styles from "./SettingsPage.module.css";

const PANE_IDS: SettingsPaneId[] = ["prompt", "models", "skills", "mcp", "extensions", "other", "env"];

function isNpmSkill(skill: SkillInfo): boolean {
	if (skill.toggleable === false) return true;
	const source = skill.source || "";
	if (source.startsWith("npm:")) return true;
	const path = skill.path || "";
	return path.includes("/node_modules/") || path.includes("\\node_modules\\");
}

function isSkillToggleable(skill: SkillInfo): boolean {
	return !isNpmSkill(skill) && skill.toggleable !== false;
}

function formatSkillMeta(skill: SkillInfo): string {
	const source = (skill.source || "").trim();
	if (!source || source === "auto") return "";
	return source;
}
const SETTINGS_PANE_KEY = "sproutclaw-settings-pane";

function renderNameList(label: string, items: string[] | undefined) {
	if (!Array.isArray(items) || !items.length) return null;
	return (
		<div className={styles.nameList}>
			<span>{label}</span>
			<div>
				{items.map((item) => (
					<code key={item}>{item}</code>
				))}
			</div>
		</div>
	);
}

function extensionCategory(extension: ExtensionInfo): "local" | "npm" {
	if (extension.category === "npm" || extension.category === "local") {
		return extension.category;
	}
	if (extension.source?.startsWith("npm:")) return "npm";
	const pathHint = `${extension.path || ""} ${extension.location || ""}`.replace(/\\/g, "/");
	if (pathHint.includes("/.pi/agent/npm/node_modules/")) return "npm";
	return "local";
}

function extensionTogglePath(extension: ExtensionInfo): string {
	return extension.resolvedPath || extension.path || "";
}

function ExtensionCard({
	extension,
	toggling,
	disabled,
	onToggle,
}: {
	extension: ExtensionInfo;
	toggling: boolean;
	disabled: boolean;
	onToggle: (enabled: boolean) => void;
}) {
	const meta =
		extension.kind || [extension.scope, extension.source].filter(Boolean).join(" · ");
	const enabled = extension.enabled !== false;
	const togglePath = extensionTogglePath(extension);
	const counts = (
		[
			["命令", extension.commands?.length || 0],
			["工具", extension.tools?.length || 0],
			["事件", extension.handlers?.length || 0],
			["Flags", extension.flags?.length || 0],
			["快捷键", extension.shortcuts?.length || 0],
		] as const
	).filter(([, count]) => count > 0);
	const hasDetails = ["commands", "tools", "handlers", "flags", "shortcuts"].some(
		(key) => (extension[key as keyof ExtensionInfo] as string[] | undefined)?.length,
	);

	return (
		<div className={`${styles.extensionItem} ${enabled ? "" : styles.skillItemDisabled}`}>
			<div className={styles.extensionHeader}>
				<div className={styles.extensionTitleRow}>
					<div className={styles.itemName}>{extension.name || extension.path || "未命名"}</div>
					<label className={styles.skillToggle}>
						<input
							type="checkbox"
							checked={enabled}
							disabled={!togglePath || toggling || disabled}
							onChange={(e) => {
								if (!togglePath) return;
								onToggle(e.target.checked);
							}}
						/>
						<span className={styles.skillToggleUi} aria-hidden />
						<span className={styles.skillToggleLabel}>{enabled ? "已启用" : "已禁用"}</span>
					</label>
				</div>
				{meta ? <div className={styles.extensionSubtitle}>{meta}</div> : null}
			</div>
			{counts.length ? (
				<div className={styles.extensionCounts}>
					{counts.map(([label, count]) => (
						<span key={label}>
							{label} {count}
						</span>
					))}
				</div>
			) : null}
			{hasDetails ? (
				<details className={styles.extensionDetails}>
					<summary>查看注册项</summary>
					{renderNameList("命令", extension.commands)}
					{renderNameList("工具", extension.tools)}
					{renderNameList("事件", extension.handlers)}
					{renderNameList("Flags", extension.flags)}
					{renderNameList("快捷键", extension.shortcuts)}
				</details>
			) : null}
			{extension.location ? <div className={styles.itemPath}>{extension.location}</div> : null}
		</div>
	);
}

function ExtensionGroup({
	title,
	items,
	emptyText,
	togglingPath,
	disabled,
	onToggle,
}: {
	title: string;
	items: ExtensionInfo[];
	emptyText: string;
	togglingPath: string | null;
	disabled: boolean;
	onToggle: (path: string, enabled: boolean) => void;
}) {
	return (
		<section className={styles.extensionGroup}>
			<div className={styles.extensionGroupHeader}>
				<h3>{title}</h3>
				<span>{items.length} 个</span>
			</div>
			{items.length ? (
				<div className={styles.extensionGroupList}>
					{items.map((extension) => {
						const togglePath = extensionTogglePath(extension);
						return (
							<ExtensionCard
								key={togglePath || extension.location || extension.name}
								extension={extension}
								toggling={Boolean(togglePath && togglingPath === togglePath)}
								disabled={disabled}
								onToggle={(enabled) => {
									if (!togglePath) return;
									onToggle(togglePath, enabled);
								}}
							/>
						);
					})}
				</div>
			) : (
				<div className={`${styles.empty} ${styles.emptyCompact}`}>{emptyText}</div>
			)}
		</section>
	);
}

function McpToolItem({
	tool,
	serverEnabled,
	toggling,
	disabled,
	onToggle,
}: {
	tool: McpToolInfo;
	serverEnabled: boolean;
	toggling: boolean;
	disabled: boolean;
	onToggle: (enabled: boolean) => void;
}) {
	const params = Array.isArray(tool.parameters) ? tool.parameters : [];
	const required = new Set(Array.isArray(tool.required) ? tool.required : []);
	const description = String(tool.description || "").replace(/\s+/g, " ").trim();
	const shortDescription =
		description.length > 86 ? `${description.slice(0, 86).trimEnd()}...` : description;
	const title = [tool.name, description, params.length ? `参数: ${params.join(", ")}` : ""]
		.filter(Boolean)
		.join("\n");
	const enabled = tool.enabled !== false;
	const toolName = tool.name || "";

	return (
		<details
			className={`${styles.mcpToolItem} ${enabled ? "" : styles.mcpToolItemDisabled}`}
			title={title}
		>
			<summary className={styles.mcpToolSummary}>
				<span className={styles.mcpToolName}>{toolName || "未命名工具"}</span>
				<div className={styles.mcpToolSummaryActions}>
					{params.length ? <span className={styles.badge}>{params.length} 参数</span> : null}
					<label
						className={styles.skillToggle}
						onClick={(e) => e.stopPropagation()}
						onKeyDown={(e) => e.stopPropagation()}
					>
						<input
							type="checkbox"
							checked={enabled}
							disabled={!toolName || !serverEnabled || toggling || disabled}
							onChange={(e) => {
								if (!toolName || !serverEnabled) return;
								onToggle(e.target.checked);
							}}
						/>
						<span className={styles.skillToggleUi} aria-hidden />
						<span className={styles.skillToggleLabel}>{enabled ? "开" : "关"}</span>
					</label>
				</div>
			</summary>
			{shortDescription ? <div className={styles.mcpToolDesc}>{shortDescription}</div> : null}
			{params.length ? (
				<div className={styles.mcpParamList}>
					{params.map((param) => (
						<code key={param}>
							{param}
							{required.has(param) ? "*" : ""}
						</code>
					))}
				</div>
			) : null}
		</details>
	);
}

export function SettingsPage() {
	const { markRouteReady } = useBootstrap();
	const { updateAvatars } = useAvatars();
	const [activePane, setActivePane] = useState<SettingsPaneId>("prompt");
	const [systemPrompt, setSystemPrompt] = useState("");
	const [systemPromptPath, setSystemPromptPath] = useState("");
	const [modelsConfig, setModelsConfig] = useState("");
	const [modelsConfigPath, setModelsConfigPath] = useState("");
	const [userAvatarUrl, setUserAvatarUrl] = useState("");
	const [agentAvatarUrl, setAgentAvatarUrl] = useState("");
	const [skills, setSkills] = useState<SkillInfo[]>([]);
	const [mcpTools, setMcpTools] = useState<McpServerInfo[]>([]);
	const [extensions, setExtensions] = useState<ExtensionInfo[]>([]);
	const [extensionsPath, setExtensionsPath] = useState("");
	const [statusText, setStatusText] = useState("");
	const [statusKind, setStatusKind] = useState<"" | "ok" | "error">("");
	const [loading, setLoading] = useState(true);
	const [saving, setSaving] = useState(false);
	const [savingModels, setSavingModels] = useState(false);
	const [savingAvatars, setSavingAvatars] = useState(false);
	const [reloading, setReloading] = useState(false);
	const [togglingSkillPath, setTogglingSkillPath] = useState<string | null>(null);
	const [togglingMcpServer, setTogglingMcpServer] = useState<string | null>(null);
	const [togglingMcpTool, setTogglingMcpTool] = useState<string | null>(null);
	const [togglingExtensionPath, setTogglingExtensionPath] = useState<string | null>(null);
	const [envInfo, setEnvInfo] = useState<EnvironmentInfo | null>(null);
	const [loadingEnv, setLoadingEnv] = useState(false);

	useEffect(() => {
		let initial: SettingsPaneId = "prompt";
		try {
			const saved = sessionStorage.getItem(SETTINGS_PANE_KEY);
			if (saved && PANE_IDS.includes(saved as SettingsPaneId)) {
				initial = saved as SettingsPaneId;
			}
		} catch {
			/* ignore */
		}
		setActivePane(initial);
	}, []);

	const setStatus = (text: string, kind: "" | "ok" | "error" = "") => {
		setStatusText(text);
		setStatusKind(kind);
	};

	const showPane = (paneId: SettingsPaneId) => {
		setActivePane(paneId);
		try {
			sessionStorage.setItem(SETTINGS_PANE_KEY, paneId);
		} catch {
			/* ignore */
		}
	};

	const loadSettings = useCallback(async () => {
		setLoading(true);
		setStatus("");
		try {
			const data = await settingsApi.fetchSettings();
			setSystemPrompt(data.systemPrompt || "");
			setSystemPromptPath(data.systemPromptPath || "");
			setModelsConfig(data.modelsConfig || "");
			setModelsConfigPath(data.modelsConfigPath || "");
			setUserAvatarUrl(data.userAvatarUrl || "");
			setAgentAvatarUrl(data.agentAvatarUrl || "");
			updateAvatars({
				userAvatarUrl: data.userAvatarUrl || "",
				agentAvatarUrl: data.agentAvatarUrl || "",
			});
			setSkills(data.skills || []);
			setMcpTools(data.mcpTools || []);
			setExtensions(data.extensions || []);
			setExtensionsPath(data.extensionsPath || "");
		} catch (err) {
			setStatus(`加载设置失败: ${err instanceof Error ? err.message : String(err)}`, "error");
		} finally {
			setLoading(false);
			markRouteReady("settings");
		}
	}, [markRouteReady, updateAvatars]);

	const reloadSettings = async () => {
		setReloading(true);
		setStatus("正在重新加载 Agent 资源...");
		try {
			await settingsApi.reloadSettings();
			await loadSettings();
			setStatus("已重新加载并刷新设置", "ok");
		} catch (err) {
			setStatus(`重新加载失败: ${err instanceof Error ? err.message : String(err)}`, "error");
		} finally {
			setReloading(false);
		}
	};

	const loadEnvInfo = async () => {
		setLoadingEnv(true);
		try {
			const data = await settingsApi.fetchEnvironment();
			setEnvInfo(data);
		} catch (err) {
			setStatus(`加载环境信息失败: ${err instanceof Error ? err.message : String(err)}`, "error");
		} finally {
			setLoadingEnv(false);
		}
	};

	useEffect(() => {
		if (activePane === "env" && !envInfo && !loadingEnv) {
			void loadEnvInfo();
		}
	}, [activePane]);

	const toggleSkillEnabled = async (path: string, enabled: boolean) => {
		setTogglingSkillPath(path);
		setStatus(enabled ? "正在启用 skill…" : "正在禁用 skill…");
		try {
			const data = await settingsApi.toggleSkill(path, enabled);
			if (data.skill) {
				setSkills((prev) =>
					prev.map((skill) => (skill.path === path ? { ...skill, ...data.skill } : skill)),
				);
			} else {
				await loadSettings();
			}
			setStatus(enabled ? "Skill 已启用" : "Skill 已禁用", "ok");
		} catch (err) {
			setStatus(`切换失败: ${err instanceof Error ? err.message : String(err)}`, "error");
		} finally {
			setTogglingSkillPath(null);
		}
	};

	const updateMcpServer = (entry: McpServerInfo) => {
		setMcpTools((prev) =>
			prev.map((server) => (server.name === entry.name ? { ...server, ...entry } : server)),
		);
	};

	const toggleMcpServerEnabled = async (serverName: string, enabled: boolean) => {
		setTogglingMcpServer(serverName);
		setStatus(enabled ? "正在启用 MCP Server…" : "正在禁用 MCP Server…");
		try {
			const data = await settingsApi.toggleMcpServer(serverName, enabled);
			if (data.server) {
				updateMcpServer(data.server);
			} else {
				await loadSettings();
			}
			setStatus(
				enabled
					? "MCP Server 已启用，必要时可运行 /mcp reconnect 刷新连接"
					: "MCP Server 已禁用",
				"ok",
			);
		} catch (err) {
			setStatus(`切换失败: ${err instanceof Error ? err.message : String(err)}`, "error");
		} finally {
			setTogglingMcpServer(null);
		}
	};

	const toggleMcpToolEnabled = async (serverName: string, toolName: string, enabled: boolean) => {
		const toggleKey = `${serverName}/${toolName}`;
		setTogglingMcpTool(toggleKey);
		setStatus(enabled ? "正在启用 MCP工具…" : "正在禁用 MCP工具…");
		try {
			const data = await settingsApi.toggleMcpTool(serverName, toolName, enabled);
			if (data.tool) {
				setMcpTools((prev) =>
					prev.map((server) => {
						if (server.name !== serverName || !Array.isArray(server.tools)) return server;
						const tools = server.tools.map((tool) =>
							tool.name === toolName ? { ...tool, ...data.tool } : tool,
						);
						const enabledToolCount = tools.filter((tool) => tool.enabled !== false).length;
						return { ...server, tools, enabledToolCount };
					}),
				);
			} else {
				await loadSettings();
			}
			setStatus(enabled ? "MCP工具已启用" : "MCP工具已禁用", "ok");
		} catch (err) {
			setStatus(`切换失败: ${err instanceof Error ? err.message : String(err)}`, "error");
		} finally {
			setTogglingMcpTool(null);
		}
	};

	const toggleExtensionEnabled = async (path: string, enabled: boolean) => {
		setTogglingExtensionPath(path);
		setStatus(enabled ? "正在启用扩展…" : "正在禁用扩展…");
		try {
			const data = await settingsApi.toggleExtension(path, enabled);
			if (data.extension) {
				setExtensions((prev) =>
					prev.map((extension) => {
						const key = extensionTogglePath(extension);
						return key === path ? { ...extension, ...data.extension } : extension;
					}),
				);
			} else {
				await loadSettings();
			}
			setStatus(enabled ? "扩展已启用，Agent 已重新加载" : "扩展已禁用，Agent 已重新加载", "ok");
		} catch (err) {
			setStatus(`切换失败: ${err instanceof Error ? err.message : String(err)}`, "error");
		} finally {
			setTogglingExtensionPath(null);
		}
	};

	const saveSystemPrompt = async () => {
		setSaving(true);
		setStatus("保存中...");
		try {
			const data = await settingsApi.saveSystemPrompt(systemPrompt);
			if (data.systemPromptPath) setSystemPromptPath(data.systemPromptPath);
			setStatus("已保存，Agent 已重新加载", "ok");
		} catch (err) {
			setStatus(`保存失败: ${err instanceof Error ? err.message : String(err)}`, "error");
		} finally {
			setSaving(false);
		}
	};

	const saveModelsConfig = async () => {
		setSavingModels(true);
		setStatus("保存中...");
		try {
			const data = await settingsApi.saveModelsConfig(modelsConfig);
			if (data.modelsConfigPath) setModelsConfigPath(data.modelsConfigPath);
			const refreshed = await settingsApi.fetchSettings();
			setModelsConfig(refreshed.modelsConfig || "");
			setStatus("已保存，Agent 已重新加载", "ok");
		} catch (err) {
			setStatus(`保存失败: ${err instanceof Error ? err.message : String(err)}`, "error");
		} finally {
			setSavingModels(false);
		}
	};

	const saveAvatars = async () => {
		setSavingAvatars(true);
		setStatus("保存中...");
		try {
			const data = await settingsApi.saveAvatars({ userAvatarUrl, agentAvatarUrl });
			const next = {
				userAvatarUrl: data.userAvatarUrl || "",
				agentAvatarUrl: data.agentAvatarUrl || "",
			};
			setUserAvatarUrl(next.userAvatarUrl);
			setAgentAvatarUrl(next.agentAvatarUrl);
			updateAvatars(next);
			setStatus("头像设置已保存", "ok");
		} catch (err) {
			setStatus(`保存失败: ${err instanceof Error ? err.message : String(err)}`, "error");
		} finally {
			setSavingAvatars(false);
		}
	};

	useEffect(() => {
		void loadSettings();
	}, [loadSettings]);

	const toolTotal = mcpTools.reduce((sum, server) => sum + (server.toolCount || 0), 0);
	const enabledMcpServerCount = mcpTools.filter((server) => server.enabled !== false).length;
	const enabledMcpToolCount = mcpTools.reduce(
		(sum, server) => sum + (server.enabled !== false ? server.enabledToolCount ?? 0 : 0),
		0,
	);
	const localExtensions = extensions.filter((extension) => extensionCategory(extension) === "local");
	const npmExtensions = extensions.filter((extension) => extensionCategory(extension) === "npm");
	const toggleableSkills = skills.filter(isSkillToggleable);
	const enabledSkillCount = toggleableSkills.filter((skill) => skill.enabled !== false).length;
	const enabledExtensionCount = extensions.filter((extension) => extension.enabled !== false).length;
	const statusClass =
		statusKind === "ok" ? styles.statusOk : statusKind === "error" ? styles.statusError : "";

	return (
		<div className={styles.page}>
			<main className={styles.main}>
				<header className={styles.pageHeader}>
					<div className={styles.pageTitle}>
						<img className={styles.logo} src="/logo.png" width={34} height={34} alt="" decoding="async" />
						<div>
							<h1>设置</h1>
						</div>
					</div>
					<Link to="/" className={`${styles.secondaryBtn} ${styles.linkBtn}`}>
						返回
					</Link>
				</header>

				<div className={styles.shell}>
					<div className={styles.layout}>
						<nav className={styles.sidebar} role="tablist" aria-label="设置分区">
							{(
								[
									["prompt", "系统提示词"],
									["models", "模型配置"],
									["skills", "Skills"],
									["mcp", "MCP工具"],
									["extensions", "插件扩展"],
									["other", "其他设置"],
									["env", "环境信息"],
								] as const
							).map(([id, label]) => (
								<button
									key={id}
									type="button"
									role="tab"
									aria-selected={activePane === id}
									className={`${styles.navBtn} ${activePane === id ? styles.navBtnActive : ""}`}
									onClick={() => showPane(id)}
								>
									{label}
								</button>
							))}
						</nav>

						<div className={styles.panes}>
							<section
								className={`${styles.pane} ${styles.panel} ${activePane === "prompt" ? styles.paneActive : ""}`}
								role="tabpanel"
								hidden={activePane !== "prompt"}
							>
								<div className={styles.panelHeader}>
									<div>
										<h2>系统提示词</h2>
										<p>{systemPromptPath}</p>
									</div>
									<button
										type="button"
										className={styles.primaryBtn}
										disabled={saving}
										onClick={() => void saveSystemPrompt()}
									>
										保存
									</button>
								</div>
								<textarea
									className={styles.textarea}
									spellCheck={false}
									aria-label="系统提示词"
									value={systemPrompt}
									onChange={(e) => setSystemPrompt(e.target.value)}
								/>
								{statusText && activePane === "prompt" ? (
									<div className={`${styles.status} ${statusClass}`}>{statusText}</div>
								) : null}
							</section>

							<section
								className={`${styles.pane} ${styles.panel} ${activePane === "models" ? styles.paneActive : ""}`}
								role="tabpanel"
								hidden={activePane !== "models"}
							>
								<div className={styles.panelHeader}>
									<div>
										<h2>模型配置</h2>
										<p>{modelsConfigPath}</p>
									</div>
									<button
										type="button"
										className={styles.primaryBtn}
										disabled={savingModels}
										onClick={() => void saveModelsConfig()}
									>
										保存
									</button>
								</div>
								<textarea
									className={styles.textarea}
									spellCheck={false}
									aria-label="模型配置"
									value={modelsConfig}
									onChange={(e) => setModelsConfig(e.target.value)}
								/>
								{statusText && activePane === "models" ? (
									<div className={`${styles.status} ${statusClass}`}>{statusText}</div>
								) : null}
							</section>

							<section
								className={`${styles.pane} ${styles.panel} ${activePane === "skills" ? styles.paneActive : ""}`}
								role="tabpanel"
								hidden={activePane !== "skills"}
							>
								<div className={styles.panelHeader}>
									<div>
										<h2>Skills</h2>
										<p>
											{enabledSkillCount} / {toggleableSkills.length} 个已启用
										</p>
									</div>
									<button
										type="button"
										className={styles.secondaryBtn}
										disabled={reloading}
										onClick={() => void reloadSettings()}
									>
										刷新
									</button>
								</div>
								<div className={styles.list}>
									{loading ? (
										<div className={styles.empty}>加载中...</div>
									) : !skills.length ? (
										<div className={styles.empty}>暂无已加载 skills</div>
									) : (
										skills.map((skill) => {
											const meta = formatSkillMeta(skill);
											const skillPath = skill.path || "";
											const enabled = skill.enabled !== false;
											const toggleable = isSkillToggleable(skill);
											const toggling = togglingSkillPath === skillPath;
											return (
												<div
													key={skillPath || skill.name || skill.command}
													className={`${styles.skillItem} ${enabled ? "" : styles.skillItemDisabled}`}
												>
													<div className={styles.titleRow}>
														<div className={styles.itemName}>
															{skill.name || skill.command || "未命名"}
														</div>
														<div className={styles.skillActions}>
															{meta ? <div className={styles.itemMeta}>{meta}</div> : null}
															{toggleable ? (
																<label className={styles.skillToggle}>
																	<input
																		type="checkbox"
																		checked={enabled}
																		disabled={!skillPath || toggling || reloading}
																		onChange={(e) => {
																			if (!skillPath) return;
																			void toggleSkillEnabled(skillPath, e.target.checked);
																		}}
																	/>
																	<span className={styles.skillToggleUi} aria-hidden />
																	<span className={styles.skillToggleLabel}>
																		{enabled ? "已启用" : "已禁用"}
																	</span>
																</label>
															) : null}
														</div>
													</div>
													{skill.description ? (
														<div className={styles.itemDesc}>{skill.description}</div>
													) : null}
													{skill.path ? <div className={styles.itemPath}>{skill.path}</div> : null}
												</div>
											);
										})
									)}
								</div>
							</section>

							<section
								className={`${styles.pane} ${styles.panel} ${activePane === "mcp" ? styles.paneActive : ""}`}
								role="tabpanel"
								hidden={activePane !== "mcp"}
							>
								<div className={styles.panelHeader}>
									<div>
										<h2>MCP工具</h2>
										<p>
											{enabledMcpServerCount} / {mcpTools.length} 个 Server · {enabledMcpToolCount} /{" "}
											{toolTotal} 个工具已启用
										</p>
									</div>
									<button
										type="button"
										className={styles.secondaryBtn}
										disabled={reloading}
										onClick={() => void reloadSettings()}
									>
										刷新
									</button>
								</div>
								<div className={styles.list}>
									{loading ? (
										<div className={styles.empty}>加载中...</div>
									) : !mcpTools.length ? (
										<div className={styles.empty}>暂无 MCP server 配置</div>
									) : (
										mcpTools.map((server) => {
											const tools = Array.isArray(server.tools) ? server.tools : [];
											const serverName = server.name || "";
											const serverEnabled = server.enabled !== false;
											const togglingServer = togglingMcpServer === serverName;
											const status = server.cached ? "已缓存" : "未连接";
											const cachedAt = server.cachedAt
												? new Date(server.cachedAt).toLocaleString()
												: "";
											return (
												<div
													key={serverName || "unnamed"}
													className={`${styles.mcpServerItem} ${serverEnabled ? "" : styles.skillItemDisabled}`}
												>
													<div className={styles.mcpServerHead}>
														<div className={styles.mcpServerMain}>
															<div className={styles.titleRow}>
																<div className={styles.itemName}>
																	{serverName || "未命名 Server"}
																</div>
																<label className={styles.skillToggle}>
																	<input
																		type="checkbox"
																		checked={serverEnabled}
																		disabled={!serverName || togglingServer || reloading}
																		onChange={(e) => {
																			if (!serverName) return;
																			void toggleMcpServerEnabled(serverName, e.target.checked);
																		}}
																	/>
																	<span className={styles.skillToggleUi} aria-hidden />
																	<span className={styles.skillToggleLabel}>
																		{serverEnabled ? "已启用" : "已禁用"}
																	</span>
																</label>
															</div>
															{cachedAt ? (
																<div className={styles.mcpServerSub}>更新 {cachedAt}</div>
															) : null}
														</div>
														<div className={styles.mcpServerBadges}>
															<span className={styles.badge}>{status}</span>
															<span className={styles.badge}>
																{serverEnabled
																	? `${server.enabledToolCount ?? tools.filter((tool) => tool.enabled !== false).length} / ${server.toolCount || tools.length} 工具`
																	: `${server.toolCount || tools.length} 工具`}
															</span>
															{server.resourceCount ? (
																<span className={styles.badge}>{server.resourceCount} 资源</span>
															) : null}
														</div>
													</div>
													{tools.length ? (
														<div className={styles.mcpToolList}>
															{tools.map((tool) => {
																const toolName = tool.name || "";
																const toggleKey = `${serverName}/${toolName}`;
																return (
																	<McpToolItem
																		key={toolName || "unnamed"}
																		tool={tool}
																		serverEnabled={serverEnabled}
																		toggling={togglingMcpTool === toggleKey}
																		disabled={reloading || togglingServer}
																		onToggle={(enabled) => {
																			if (!serverName || !toolName) return;
																			void toggleMcpToolEnabled(serverName, toolName, enabled);
																		}}
																	/>
																);
															})}
														</div>
													) : (
														<div className={`${styles.empty} ${styles.emptyCompact}`}>
															暂无已缓存工具，运行 /mcp reconnect 后刷新。
														</div>
													)}
												</div>
											);
										})
									)}
								</div>
								{statusText && activePane === "mcp" ? (
									<div className={`${styles.status} ${statusClass}`}>{statusText}</div>
								) : null}
							</section>

							<section
								className={`${styles.pane} ${styles.panel} ${activePane === "extensions" ? styles.paneActive : ""}`}
								role="tabpanel"
								hidden={activePane !== "extensions"}
							>
								<div className={styles.panelHeader}>
									<div>
										<h2>插件扩展</h2>
										<p>
											{enabledExtensionCount} / {extensions.length} 个已启用 · {localExtensions.length}{" "}
											个本地 · {npmExtensions.length} 个 npm
											{extensionsPath ? ` · ${extensionsPath}` : ""}
										</p>
									</div>
									<button
										type="button"
										className={styles.secondaryBtn}
										disabled={reloading}
										onClick={() => void reloadSettings()}
									>
										刷新
									</button>
								</div>
								<div className={styles.list}>
									{loading ? (
										<div className={styles.empty}>加载中...</div>
									) : !extensions.length ? (
										<div className={styles.empty}>暂无已加载插件扩展</div>
									) : (
										<>
											<ExtensionGroup
												title="本地扩展"
												items={localExtensions}
												emptyText="暂无本地扩展"
												togglingPath={togglingExtensionPath}
												disabled={reloading}
												onToggle={(path, enabled) => void toggleExtensionEnabled(path, enabled)}
											/>
											<ExtensionGroup
												title="npm 扩展"
												items={npmExtensions}
												emptyText="暂无 npm 扩展"
												togglingPath={togglingExtensionPath}
												disabled={reloading}
												onToggle={(path, enabled) => void toggleExtensionEnabled(path, enabled)}
											/>
										</>
									)}
								</div>
								{statusText && activePane === "extensions" ? (
									<div className={`${styles.status} ${statusClass}`}>{statusText}</div>
								) : null}
							</section>

							<section
								className={`${styles.pane} ${styles.panel} ${activePane === "other" ? styles.paneActive : ""}`}
								role="tabpanel"
								hidden={activePane !== "other"}
							>
								<div className={styles.panelHeader}>
									<div>
										<h2>其他设置</h2>
										<p>聊天头像使用网页图片链接</p>
									</div>
									<button
										type="button"
										className={styles.primaryBtn}
										disabled={savingAvatars}
										onClick={() => void saveAvatars()}
									>
										保存
									</button>
								</div>
								<div className={styles.formBody}>
									<label className={styles.field}>
										<span className={styles.fieldLabel}>用户头像链接</span>
										<input
											className={styles.textInput}
											type="url"
											inputMode="url"
											placeholder="https://example.com/user-avatar.png"
											value={userAvatarUrl}
											onChange={(e) => setUserAvatarUrl(e.target.value)}
										/>
										{userAvatarUrl.trim() ? (
											<div className={styles.avatarPreviewRow}>
												<img
													className={styles.avatarPreview}
													src={userAvatarUrl.trim()}
													alt=""
													decoding="async"
												/>
												<span className={styles.previewHint}>预览</span>
											</div>
										) : null}
									</label>
									<label className={styles.field}>
										<span className={styles.fieldLabel}>Agent 头像链接</span>
										<input
											className={styles.textInput}
											type="url"
											inputMode="url"
											placeholder="https://example.com/agent-avatar.png"
											value={agentAvatarUrl}
											onChange={(e) => setAgentAvatarUrl(e.target.value)}
										/>
										{agentAvatarUrl.trim() ? (
											<div className={styles.avatarPreviewRow}>
												<img
													className={styles.avatarPreview}
													src={agentAvatarUrl.trim()}
													alt=""
													decoding="async"
												/>
												<span className={styles.previewHint}>预览</span>
											</div>
										) : null}
									</label>
									<p className={styles.fieldHint}>
										留空则不显示对应头像。仅支持 http / https 图片链接。
									</p>
								</div>
								{statusText && activePane === "other" ? (
									<div className={`${styles.status} ${statusClass}`}>{statusText}</div>
								) : null}
							</section>

							<section
								className={`${styles.pane} ${styles.panel} ${activePane === "env" ? styles.paneActive : ""}`}
								role="tabpanel"
								hidden={activePane !== "env"}
							>
								<div className={styles.panelHeader}>
									<div>
										<h2>环境信息</h2>
										<p>Node.js 运行时 · 操作系统 · 进程信息</p>
									</div>
									<button
										type="button"
										className={styles.secondaryBtn}
										disabled={loadingEnv}
										onClick={() => void loadEnvInfo()}
									>
										刷新
									</button>
								</div>
								<div className={styles.formBody}>
									{loadingEnv ? (
										<div className={styles.empty}>加载中...</div>
									) : !envInfo ? (
										<div className={styles.empty}>暂无数据</div>
									) : (
										<div className={styles.envGrid}>
											{(
												[
													["Node.js 版本", envInfo.nodeVersion],
													["平台", envInfo.platform],
													["架构", envInfo.arch],
													["系统类型", envInfo.osType],
													["系统版本", envInfo.osRelease],
													["主机名", envInfo.hostname],
													["进程 PID", envInfo.pid !== undefined ? String(envInfo.pid) : undefined],
													["运行时长", envInfo.uptime !== undefined ? envInfo.uptime + " 秒" : undefined],
													["总内存", envInfo.totalMemMb !== undefined ? envInfo.totalMemMb + " MB" : undefined],
													["空闲内存", envInfo.freeMemMb !== undefined ? envInfo.freeMemMb + " MB" : undefined],
													["Node 路径", envInfo.execPath],
													["工作目录", envInfo.cwd],
												] as [string, string | undefined][]
											)
												.filter(([, v]) => v !== undefined && v !== "")
												.map(([label, value]) => (
													<div key={label} className={styles.envRow}>
														<span className={styles.envLabel}>{label}</span>
														<code className={styles.envValue}>{value}</code>
													</div>
												))}
										</div>
									)}
								</div>
								{statusText && activePane === "env" ? (
									<div className={`${styles.status} ${statusClass}`}>{statusText}</div>
								) : null}
							</section>
						</div>
					</div>
				</div>
			</main>
		</div>
	);
}
