import { useState, useEffect } from "react";
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import { open as openFileDialog } from "@tauri-apps/plugin-dialog";
import {
  getServers, addServer, editServer, deleteServer,
  getServerProjectLinks, getProjects, getSettings, updateSettings,
  checkVscodeStatus, openVscodeRemote, openServerTerminal, syncSshConfig,
  parseSshConfigEntries, importSshConfigEntries,
  type Server, type SaveServerInput, type QuickLink, type SshConfigEntry,
} from "../../lib/commands";
import { useUIStore } from "../../store/ui";

import { ServiceConfigPanel } from "./ServiceConfigBlock";
import { HostAppsPanel } from "./HostAppsPanel";

function CopyBtn({ value }: { value: string }) {
  const [copied, setCopied] = useState(false);
  const handleCopy = async () => {
    await navigator.clipboard.writeText(value);
    setCopied(true);
    setTimeout(() => setCopied(false), 1500);
  };
  return (
    <button onClick={handleCopy}
      className="shrink-0 px-1.5 py-0.5 rounded text-[11px] border border-gray-200 text-gray-400 hover:text-blue-500 hover:border-blue-300 hover:bg-blue-50 transition-colors">
      {copied ? "已复制" : "复制"}
    </button>
  );
}

function buildSshCommand(s: Server): string {
  const port = s.server_port && s.server_port !== "22" ? ` -p ${s.server_port}` : "";
  const key = s.ssh_key_path ? ` -i ${s.ssh_key_path}` : "";
  const user = s.username ? `${s.username}@` : "";
  return `ssh ${user}${s.server_host}${port}${key}`;
}

function buildDeployKeyCommand(s: Server, globalKeyPath?: string): string {
  const rawKey = s.ssh_key_path || globalKeyPath || "";
  const keyPub = rawKey
    ? rawKey.replace(/(?:\.pub)?$/, ".pub")
    : "%USERPROFILE%\\.ssh\\id_ed25519.pub";
  const portFlag = s.server_port && s.server_port !== "22" ? ` -p ${s.server_port}` : "";
  const user = s.username ? `${s.username}@` : "";
  return `type ${keyPub} | ssh${portFlag} ${user}${s.server_host} "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"`;
}

// ── SSH 密钥配置区域 ────────────────────────────────────────────────────────

function SshKeySetup({ keyPath, onKeyPathChange }: {
  keyPath: string;
  onKeyPathChange: (path: string) => void;
}) {
  const [showGuide, setShowGuide] = useState(false);

  const handleBrowse = async () => {
    const selected = await openFileDialog({
      title: "选择 SSH 私钥文件",
      defaultPath: "C:\\Users",
      filters: [
        { name: "SSH Key", extensions: ["pem", "key", "*"] },
        { name: "所有文件", extensions: ["*"] },
      ],
      multiple: false,
      directory: false,
    });
    if (selected) {
      onKeyPathChange(selected as string);
    }
  };

  const hasKey = !!keyPath;

  return (
    <div className="bg-white border border-gray-200 rounded-xl overflow-hidden">
      <div className="flex items-center gap-3 px-5 py-3 border-b border-gray-100 bg-gray-50/60">
        <span className="text-sm font-bold text-gray-800">SSH 密钥配置</span>
        {hasKey ? (
          <span className="text-[11px] px-2 py-0.5 rounded-full bg-green-50 text-green-600 border border-green-200 font-medium">
            已配置
          </span>
        ) : (
          <span className="text-[11px] px-2 py-0.5 rounded-full bg-amber-50 text-amber-600 border border-amber-200 font-medium">
            未配置
          </span>
        )}
      </div>

      <div className="px-5 py-4 space-y-3">
        {/* 密钥路径选择 */}
        <div className="flex items-center gap-3">
          <label className="text-[11px] text-gray-400 font-medium shrink-0 w-16 text-right">私钥路径</label>
          <input
            value={keyPath}
            onChange={(e) => onKeyPathChange(e.target.value)}
            placeholder="例: C:\Users\你的用户名\.ssh\id_ed25519"
            className="text-xs px-2.5 py-2 rounded-md border border-gray-200 bg-gray-50 focus:outline-none focus:border-blue-300 flex-1 font-mono"
          />
          <button onClick={handleBrowse}
            className="px-3 py-2 rounded-md text-xs border border-gray-200 text-gray-500 hover:bg-gray-50 transition-colors shrink-0">
            浏览…
          </button>
        </div>

        {hasKey && (
          <div className="flex items-center gap-3">
            <span className="text-[11px] text-gray-400 font-medium shrink-0 w-16 text-right">公钥路径</span>
            <span className="text-xs font-mono text-gray-500">
              {keyPath.replace(/(?:\.pub)?$/, ".pub")}
            </span>
          </div>
        )}

        {/* 生成教程 */}
        <details className="group" open={showGuide} onToggle={(e) => setShowGuide((e.target as HTMLDetailsElement).open)}>
          <summary className="text-[11px] text-blue-500 cursor-pointer hover:text-blue-700 transition-colors select-none flex items-center gap-1">
            <span className="text-blue-400 group-open:rotate-90 transition-transform inline-block">&#9654;</span>
            {hasKey ? "查看密钥生成教程" : "还没有密钥？点击查看如何生成"}
          </summary>
          <div className="mt-2 bg-gray-50 border border-gray-100 rounded-lg p-4 space-y-3">
            <div>
              <p className="text-xs font-semibold text-gray-700 mb-1">第 1 步：生成密钥对</p>
              <p className="text-[11px] text-gray-500 mb-1.5">在本地 CMD 或 PowerShell 中执行（<code className="text-gray-600">ed25519</code> 是加密算法名称，目前最推荐的算法，安全性高且密钥短）：</p>
              <div className="flex items-center gap-2 px-3 py-2 bg-gray-800 rounded-md">
                <span className="text-[11px] text-green-400 font-mono flex-1">ssh-keygen -t ed25519</span>
                <CopyBtn value="ssh-keygen -t ed25519" />
              </div>
              <p className="text-[10px] text-gray-400 mt-1">连按三次回车使用默认路径和空密码。一套密钥对可用于所有服务器。生成后会得到两个文件：</p>
              <ul className="text-[10px] text-gray-400 ml-3 mt-0.5 space-y-0.5">
                <li>私钥：<code className="text-gray-600">C:\Users\你的用户名\.ssh\id_ed25519</code>（自己留着）</li>
                <li>公钥：<code className="text-gray-600">C:\Users\你的用户名\.ssh\id_ed25519.pub</code>（放到服务器）</li>
              </ul>
            </div>
            <div>
              <p className="text-xs font-semibold text-gray-700 mb-1">第 2 步：选择私钥</p>
              <p className="text-[11px] text-gray-500">点击上方「浏览…」按钮选择刚生成的私钥文件，路径会自动保存。</p>
            </div>
            <div>
              <p className="text-xs font-semibold text-gray-700 mb-1">第 3 步：部署公钥到服务器</p>
              <p className="text-[11px] text-gray-500">配置好密钥后，每台服务器卡片下方会出现「部署公钥」命令，复制到 CMD 执行一次即可免密登录。</p>
            </div>
          </div>
        </details>
      </div>
    </div>
  );
}

// ── 服务器表单 ──────────────────────────────────────────────────────────────

function ServerForm({ initial, onSave, onCancel, saving }: {
  initial?: Server;
  onSave: (input: SaveServerInput) => void;
  onCancel: () => void;
  saving: boolean;
}) {
  const [name, setName] = useState(initial?.name ?? "");
  const [host, setHost] = useState(initial?.server_host ?? "");
  const [port, setPort] = useState(initial?.server_port ?? "22");
  const [username, setUsername] = useState(initial?.username ?? "");
  const [password, setPassword] = useState(initial?.password ?? "");
  const [sshKeyPath, setSshKeyPath] = useState(initial?.ssh_key_path ?? "");
  const [notes, setNotes] = useState(initial?.notes ?? "");
  const [quickLinks, setQuickLinks] = useState<QuickLink[]>(() => {
    try { return initial?.quick_links ? JSON.parse(initial.quick_links) : []; } catch { return []; }
  });

  const addLink = () => setQuickLinks((p) => [...p, { label: "", url: "" }]);
  const removeLink = (i: number) => setQuickLinks((p) => p.filter((_, idx) => idx !== i));
  const updateLink = (i: number, f: "label" | "url", v: string) =>
    setQuickLinks((p) => p.map((l, idx) => (idx === i ? { ...l, [f]: v } : l)));

  const handleSubmit = () => {
    if (!name.trim() || !host.trim()) return;
    onSave({
      name: name.trim(),
      server_host: host.trim(),
      server_port: port || undefined,
      username: username || undefined,
      password: password || undefined,
      ssh_key_path: sshKeyPath || undefined,
      quick_links: quickLinks.filter((l) => l.url.trim()).length > 0
        ? JSON.stringify(quickLinks.filter((l) => l.url.trim()))
        : undefined,
      notes: notes || undefined,
    });
  };

  return (
    <div className="bg-white border border-gray-200 rounded-xl p-5 space-y-3">
      <div className="grid grid-cols-[72px_1fr] gap-x-3 gap-y-2 items-center">
        <label className="text-[11px] text-gray-400 text-right">名称 *</label>
        <input value={name} onChange={(e) => setName(e.target.value)} placeholder="例: 生产服务器A"
          className="text-xs px-2.5 py-1.5 rounded border border-gray-200 bg-gray-50 focus:outline-none focus:border-gray-400" />
        <label className="text-[11px] text-gray-400 text-right">主机 *</label>
        <input value={host} onChange={(e) => setHost(e.target.value)} placeholder="例: 192.168.1.100"
          className="text-xs px-2.5 py-1.5 rounded border border-gray-200 bg-gray-50 focus:outline-none focus:border-gray-400" />
        <label className="text-[11px] text-gray-400 text-right">端口</label>
        <input value={port} onChange={(e) => setPort(e.target.value)} placeholder="22"
          className="text-xs px-2.5 py-1.5 rounded border border-gray-200 bg-gray-50 focus:outline-none focus:border-gray-400 w-24" />
        <label className="text-[11px] text-gray-400 text-right">用户名</label>
        <input value={username} onChange={(e) => setUsername(e.target.value)} placeholder="例: root"
          className="text-xs px-2.5 py-1.5 rounded border border-gray-200 bg-gray-50 focus:outline-none focus:border-gray-400" />
        <label className="text-[11px] text-gray-400 text-right">密码</label>
        <input value={password} onChange={(e) => setPassword(e.target.value)} type="password" placeholder="选填"
          className="text-xs px-2.5 py-1.5 rounded border border-gray-200 bg-gray-50 focus:outline-none focus:border-gray-400" />
        <label className="text-[11px] text-gray-400 text-right">SSH Key</label>
        <input value={sshKeyPath} onChange={(e) => setSshKeyPath(e.target.value)} placeholder="例: ~/.ssh/id_rsa"
          className="text-xs px-2.5 py-1.5 rounded border border-gray-200 bg-gray-50 focus:outline-none focus:border-gray-400" />
        <label className="text-[11px] text-gray-400 text-right">备注</label>
        <input value={notes} onChange={(e) => setNotes(e.target.value)} placeholder="例: 阿里云 ECS"
          className="text-xs px-2.5 py-1.5 rounded border border-gray-200 bg-gray-50 focus:outline-none focus:border-gray-400" />
      </div>

      {/* 快速链接 */}
      <div>
        <div className="flex items-center justify-between mb-1.5">
          <span className="text-[11px] text-gray-400">快速链接</span>
          <button onClick={addLink}
            className="text-[11px] px-1.5 py-0.5 rounded border border-dashed border-gray-300 text-gray-400 hover:border-gray-400 hover:text-gray-600 transition-colors">
            + 添加
          </button>
        </div>
        {quickLinks.map((link, idx) => (
          <div key={idx} className="flex items-center gap-1.5 mb-1">
            <input value={link.label} onChange={(e) => updateLink(idx, "label", e.target.value)}
              placeholder="名称" className="text-xs px-2 py-1 rounded border border-gray-200 bg-gray-50 w-24 focus:outline-none focus:border-gray-400" />
            <input value={link.url} onChange={(e) => updateLink(idx, "url", e.target.value)}
              placeholder="https://..." className="text-xs px-2 py-1 rounded border border-gray-200 bg-gray-50 flex-1 focus:outline-none focus:border-gray-400" />
            <button onClick={() => removeLink(idx)}
              className="text-gray-300 hover:text-red-400 text-xs transition-colors">x</button>
          </div>
        ))}
      </div>

      <div className="flex justify-end gap-2 pt-1">
        <button onClick={onCancel}
          className="px-3 py-1.5 rounded-md text-xs border border-gray-200 text-gray-500 hover:bg-gray-50 transition-colors">
          取消
        </button>
        <button onClick={handleSubmit} disabled={saving || !name.trim() || !host.trim()}
          className="px-3 py-1.5 rounded-md text-xs border border-blue-300 bg-blue-50 text-blue-600 hover:bg-blue-100 transition-colors disabled:opacity-50">
          {saving ? "保存中…" : "保存"}
        </button>
      </div>
    </div>
  );
}

// ── 服务器卡片 ──────────────────────────────────────────────────────────────

function ServerCard({ server, onEdit, onDelete, globalKeyPath }: {
  server: Server;
  onEdit: () => void;
  onDelete: () => void;
  globalKeyPath?: string;
}) {
  const [showPwd, setShowPwd] = useState(false);
  const [confirmDelete, setConfirmDelete] = useState(false);
  const [collapsed, setCollapsed] = useState(true);

  const sshCmd = buildSshCommand(server);
  const links: QuickLink[] = (() => {
    try { return server.quick_links ? JSON.parse(server.quick_links) : []; } catch { return []; }
  })();

  // 关联的项目
  const { data: linkedProjects = [] } = useQuery({
    queryKey: ["server-projects", server.id],
    queryFn: () => getServerProjectLinks(server.id),
  });

  const { data: allProjects = [] } = useQuery({
    queryKey: ["projects"],
    queryFn: () => getProjects(),
    staleTime: 30000,
  });

  const keyPath = server.ssh_key_path || globalKeyPath;

  return (
    <div className="bg-white border border-gray-200 rounded-xl overflow-hidden shadow-sm">
      {/* ── 标题栏 ── */}
      <div className="flex items-center gap-3 px-6 py-3.5 bg-gradient-to-r from-gray-50 to-white border-b border-gray-100">
        <div className="w-8 h-8 rounded-lg bg-blue-50 border border-blue-200 flex items-center justify-center text-blue-500 text-sm shrink-0">
          {server.name.charAt(0).toUpperCase()}
        </div>
        <div className="flex-1 min-w-0">
          <div className="flex items-center gap-2">
            <span className="text-sm font-bold text-gray-800">{server.name}</span>
            {server.notes && (
              <span className="text-[11px] text-gray-400">{server.notes}</span>
            )}
          </div>
          <span className="text-xs text-gray-400 font-mono">{server.server_host}{server.server_port && server.server_port !== "22" ? `:${server.server_port}` : ""}</span>
        </div>
        <div className="flex gap-1.5 shrink-0 items-center">
          <button onClick={() => setCollapsed((v) => !v)}
            className="px-2 py-1 rounded-md text-[11px] text-gray-400 hover:text-gray-600 hover:bg-gray-100 transition-colors"
            title={collapsed ? "展开" : "折叠"}
          >
            {collapsed ? "展开 ▼" : "收起 ▲"}
          </button>
          <div className="w-px h-4 bg-gray-200" />
          <button onClick={onEdit}
            className="px-2.5 py-1 rounded-md text-[11px] border border-gray-200 text-gray-500 hover:bg-gray-50 transition-colors">
            编辑
          </button>
          {!confirmDelete ? (
            <button onClick={() => setConfirmDelete(true)}
              className="px-2.5 py-1 rounded-md text-[11px] border border-gray-200 text-gray-400 hover:text-red-500 hover:border-red-200 transition-colors">
              删除
            </button>
          ) : (
            <div className="flex gap-1">
              <button onClick={onDelete}
                className="px-2.5 py-1 rounded-md text-[11px] border border-red-300 bg-red-50 text-red-600 hover:bg-red-100 transition-colors">
                确认
              </button>
              <button onClick={() => setConfirmDelete(false)}
                className="px-2.5 py-1 rounded-md text-[11px] border border-gray-200 text-gray-400 transition-colors">
                取消
              </button>
            </div>
          )}
        </div>
      </div>

      {/* ── 内容区：左右两栏布局 ── */}
      {!collapsed && <div className="flex divide-x divide-gray-100">

        {/* 左栏：服务器信息 + 快速链接 + 关联项目 */}
        <div className="flex-1 px-6 py-4 space-y-4 min-w-0">

          {/* 服务器信息 */}
          <div>
            <h4 className="text-[11px] font-semibold text-gray-400 uppercase tracking-wider mb-2">服务器信息</h4>
            <div className="space-y-1">
              <div className="flex items-center gap-3 py-1">
                <span className="text-[11px] text-gray-400 w-10 shrink-0 text-right">主机</span>
                <span className="text-xs font-mono text-gray-800 font-medium">{server.server_host}</span>
                <CopyBtn value={server.server_host} />
              </div>
              {server.server_port && (
                <div className="flex items-center gap-3 py-1">
                  <span className="text-[11px] text-gray-400 w-10 shrink-0 text-right">端口</span>
                  <span className="text-xs font-mono text-gray-800">{server.server_port}</span>
                  <CopyBtn value={server.server_port} />
                </div>
              )}
              {server.username && (
                <div className="flex items-center gap-3 py-1">
                  <span className="text-[11px] text-gray-400 w-10 shrink-0 text-right">用户</span>
                  <span className="text-xs font-mono text-gray-800">{server.username}</span>
                  <CopyBtn value={server.username} />
                </div>
              )}
            </div>
          </div>

          {/* 快速链接 */}
          {links.length > 0 && (
            <div>
              <h4 className="text-[11px] font-semibold text-gray-400 uppercase tracking-wider mb-2">快速链接</h4>
              <div className="flex flex-wrap gap-1.5">
                {links.map((link, i) => (
                  <div key={i} className="inline-flex items-center gap-1 px-2.5 py-1 rounded-md bg-blue-50 border border-blue-100">
                    <a href={link.url} target="_blank" rel="noopener noreferrer"
                      className="text-[11px] text-blue-600 hover:text-blue-800 hover:underline transition-colors font-medium">
                      {link.label || link.url}
                    </a>
                    <CopyBtn value={link.url} />
                  </div>
                ))}
              </div>
            </div>
          )}

          {/* 关联项目 */}
          {linkedProjects.length > 0 && (
            <div>
              <h4 className="text-[11px] font-semibold text-gray-400 uppercase tracking-wider mb-2">关联项目</h4>
              <div className="flex flex-wrap gap-1.5">
                {linkedProjects.map((lp) => {
                  const proj = allProjects.find((p) => p.id === lp.project_id);
                  return (
                    <span key={lp.project_id}
                      className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-md text-[11px] bg-gray-50 text-gray-700 border border-gray-200">
                      <span className="font-medium">{proj?.name ?? lp.project_id}</span>
                      {lp.role && (
                        <span className="text-[10px] text-purple-500 bg-purple-50 px-1.5 py-0.5 rounded font-medium">{lp.role}</span>
                      )}
                    </span>
                  );
                })}
              </div>
            </div>
          )}
        </div>

        {/* 右栏：连接配置 */}
        <div className="w-[420px] shrink-0 px-6 py-4 space-y-4 bg-gray-50/30">

          {/* SSH 登录命令 */}
          <div>
            <h4 className="text-[11px] font-semibold text-gray-400 uppercase tracking-wider mb-2">SSH 登录</h4>
            <div className="flex items-center gap-2 px-3 py-2.5 bg-gray-900 rounded-lg">
              <span className="text-[11px] text-green-400 font-mono flex-1 truncate" title={sshCmd}>$ {sshCmd}</span>
              <CopyBtn value={sshCmd} />
            </div>
          </div>

          {/* 认证方式 */}
          <div className="space-y-2.5">
            <h4 className="text-[11px] font-semibold text-gray-400 uppercase tracking-wider">认证方式</h4>

            {/* 密码认证 */}
            <div className="bg-white border border-gray-200 rounded-lg px-4 py-3 space-y-1.5">
              <div className="flex items-center gap-2">
                <div className="w-1.5 h-1.5 rounded-full bg-orange-400 shrink-0" />
                <span className="text-[11px] font-semibold text-gray-700">密码认证</span>
              </div>
              {server.password ? (
                <div className="flex items-center gap-2 pl-3.5">
                  <span className="text-xs font-mono text-gray-700 flex-1">{showPwd ? server.password : "••••••••"}</span>
                  <button onClick={() => setShowPwd((v) => !v)}
                    className="px-1.5 py-0.5 rounded text-[11px] border border-gray-200 text-gray-400 hover:text-gray-600 transition-colors shrink-0">
                    {showPwd ? "隐藏" : "显示"}
                  </button>
                  <CopyBtn value={server.password} />
                </div>
              ) : (
                <p className="text-[11px] text-gray-300 pl-3.5">未设置密码</p>
              )}
            </div>

            {/* 密钥认证 */}
            <div className="bg-white border border-gray-200 rounded-lg px-4 py-3 space-y-1.5">
              <div className="flex items-center gap-2">
                <div className="w-1.5 h-1.5 rounded-full bg-green-400 shrink-0" />
                <span className="text-[11px] font-semibold text-gray-700">密钥认证</span>
                <span className="text-[10px] text-green-600 bg-green-50 px-1.5 py-0.5 rounded font-medium">免密</span>
              </div>
              {keyPath ? (
                <div className="flex items-center gap-2 pl-3.5">
                  <span className="text-[11px] font-mono text-gray-600 flex-1 truncate" title={keyPath}>{keyPath}</span>
                  {!server.ssh_key_path && globalKeyPath && (
                    <span className="text-[10px] text-gray-400 shrink-0">全局</span>
                  )}
                </div>
              ) : (
                <p className="text-[11px] text-gray-300 pl-3.5">请先在顶部配置 SSH 密钥</p>
              )}

              {/* 部署公钥 */}
              <details className="group pl-3.5">
                <summary className="text-[11px] text-blue-500 cursor-pointer hover:text-blue-700 transition-colors select-none flex items-center gap-1">
                  <span className="text-blue-400 group-open:rotate-90 transition-transform inline-block text-[10px]">&#9654;</span>
                  部署公钥到此服务器
                </summary>
                <div className="mt-1.5 flex items-start gap-2 px-3 py-2 bg-gray-900 rounded-md">
                  <span className="text-[10px] text-amber-300 font-mono flex-1 break-all leading-relaxed">
                    &gt; {buildDeployKeyCommand(server, globalKeyPath)}
                  </span>
                  <CopyBtn value={buildDeployKeyCommand(server, globalKeyPath)} />
                </div>
                <p className="text-[10px] text-gray-400 mt-1">复制到 CMD 执行一次，输入密码后即可免密登录。</p>
              </details>
            </div>
          </div>

          {/* VS Code Remote */}
          <VscodeRemoteBlock serverId={server.id} serverName={server.name} />

          {/* 宿主机应用 */}
          <HostAppsPanel serverId={server.id} />

          {/* 服务连接配置（Linux 客户端层） */}
          <ServiceConfigPanel serverId={server.id} scope="system" />

          {/* Docker 应用配置 */}
          <ServiceConfigPanel serverId={server.id} scope="docker" />
        </div>
      </div>}
    </div>
  );
}

// ── VS Code Remote 区块 ─────────────────────────────────────────────────────

function VscodeRemoteBlock({ serverId, serverName }: { serverId: string; serverName: string }) {
  const showToast = useUIStore((s) => s.showToast);
  const [remotePath, setRemotePath] = useState("");
  const [syncing, setSyncing] = useState(false);
  const [openingTerm, setOpeningTerm] = useState(false);

  const { data: vscodeStatus } = useQuery({
    queryKey: ["vscode-status"],
    queryFn: checkVscodeStatus,
    staleTime: 60000,
  });

  const handleOpen = async () => {
    try {
      setSyncing(true);
      await openVscodeRemote(serverId, remotePath || undefined);
      showToast(`VS Code Remote 已打开: ${serverName}`);
    } catch (e) {
      showToast(`${e}`);
    } finally {
      setSyncing(false);
    }
  };

  const handleOpenTerminal = async () => {
    try {
      setOpeningTerm(true);
      await openServerTerminal(serverId);
      showToast(`终端已打开: ${serverName}`);
    } catch (e) {
      showToast(`${e}`);
    } finally {
      setOpeningTerm(false);
    }
  };

  const handleSyncOnly = async () => {
    try {
      setSyncing(true);
      const path = await syncSshConfig();
      showToast(`SSH Config 已同步: ${path}`);
    } catch (e) {
      showToast(`${e}`);
    } finally {
      setSyncing(false);
    }
  };

  const installed = vscodeStatus?.installed ?? false;

  return (
    <div>
      <h4 className="text-[11px] font-semibold text-gray-400 uppercase tracking-wider mb-2">快捷操作</h4>

      <div className="bg-white border border-gray-200 rounded-lg px-4 py-3 space-y-2.5">
        {/* 状态提示 */}
        {!installed && (
          <div className="flex items-start gap-2 px-3 py-2 bg-amber-50 border border-amber-200 rounded-md">
            <span className="text-amber-500 shrink-0 mt-0.5">!</span>
            <div className="space-y-1">
              <p className="text-[11px] text-amber-700 font-medium">VS Code 未检测到</p>
              <p className="text-[10px] text-amber-600">请在炼境「设置」页面配置 VS Code 编辑器路径，或确保 <code className="font-mono bg-amber-100 px-1 rounded">code</code> 命令在系统 PATH 中。</p>
            </div>
          </div>
        )}

        {installed && (
          <div className="flex items-start gap-2 px-3 py-2 bg-blue-50 border border-blue-100 rounded-md">
            <span className="text-blue-400 shrink-0 mt-0.5 text-xs">i</span>
            <p className="text-[10px] text-blue-600">需要 VS Code 扩展 <code className="font-mono bg-blue-100 px-1 rounded">Remote - SSH</code>（ms-vscode-remote.remote-ssh）。打开 VS Code → 扩展 → 搜索安装。</p>
          </div>
        )}

        {/* 远程路径 + 打开按钮 */}
        <div className="flex items-center gap-2">
          <input
            value={remotePath}
            onChange={(e) => setRemotePath(e.target.value)}
            placeholder="远程路径（默认 /root）"
            className="text-xs px-2.5 py-2 rounded-md border border-gray-200 bg-gray-50 focus:outline-none focus:border-blue-300 flex-1 font-mono"
          />
          <button
            onClick={handleOpen}
            disabled={!installed || syncing}
            className="px-4 py-2 rounded-md text-xs font-medium bg-blue-600 text-white hover:bg-blue-700 transition-colors disabled:opacity-40 disabled:cursor-not-allowed shrink-0"
          >
            {syncing ? "连接中…" : "VS Code 打开"}
          </button>
        </div>

        {/* CMD 打开 */}
        <div className="flex items-center gap-2">
          <button
            onClick={handleOpenTerminal}
            disabled={openingTerm}
            className="px-4 py-2 rounded-md text-xs font-medium border border-gray-300 bg-gray-800 text-gray-100 hover:bg-gray-700 transition-colors disabled:opacity-40 shrink-0"
          >
            {openingTerm ? "打开中…" : "CMD 打开"}
          </button>
          <span className="text-[10px] text-gray-400">在 Windows Terminal 中 SSH 连接到此服务器</span>
        </div>

        {/* 同步 SSH Config */}
        <div className="flex items-center justify-between">
          <p className="text-[10px] text-gray-400">
            炼境会自动同步服务器信息到 <code className="font-mono text-gray-500">~/.ssh/config</code>
          </p>
          <button onClick={handleSyncOnly} disabled={syncing}
            className="text-[11px] text-gray-400 hover:text-blue-500 transition-colors disabled:opacity-50">
            手动同步
          </button>
        </div>
      </div>
    </div>
  );
}

// ── 主面板 ──────────────────────────────────────────────────────────────────

// ── 导入 SSH Config 弹窗 ────────────────────────────────────────────────────

function ImportSshConfigModal({ onClose, onImported }: { onClose: () => void; onImported: () => void }) {
  const showToast = useUIStore((s) => s.showToast);
  const [entries, setEntries] = useState<SshConfigEntry[]>([]);
  const [selected, setSelected] = useState<Set<number>>(new Set());
  const [loading, setLoading] = useState(true);
  const [importing, setImporting] = useState(false);

  useEffect(() => {
    parseSshConfigEntries()
      .then((list) => {
        setEntries(list);
        setSelected(new Set(list.map((_, i) => i))); // 默认全选
      })
      .catch((e) => showToast(`解析失败: ${e}`))
      .finally(() => setLoading(false));
  }, []);

  const toggleSelect = (idx: number) => {
    setSelected((prev) => {
      const next = new Set(prev);
      next.has(idx) ? next.delete(idx) : next.add(idx);
      return next;
    });
  };

  const toggleAll = () => {
    if (selected.size === entries.length) {
      setSelected(new Set());
    } else {
      setSelected(new Set(entries.map((_, i) => i)));
    }
  };

  const handleImport = async () => {
    const toImport = entries.filter((_, i) => selected.has(i));
    if (toImport.length === 0) return;
    setImporting(true);
    try {
      const count = await importSshConfigEntries(toImport);
      showToast(`已导入 ${count} 台服务器，SSH Config 已同步`);
      onImported();
      onClose();
    } catch (e) {
      showToast(`导入失败: ${e}`);
    } finally {
      setImporting(false);
    }
  };

  return (
    <div className="fixed inset-0 bg-black/30 z-50 flex items-center justify-center" onClick={onClose}>
      <div className="bg-white rounded-xl border border-gray-200 shadow-xl w-[600px] max-h-[70vh] flex flex-col" onClick={(e) => e.stopPropagation()}>
        {/* 标题 */}
        <div className="flex items-center justify-between px-6 py-4 border-b border-gray-100">
          <div>
            <h3 className="text-sm font-bold text-gray-800">从 SSH Config 导入</h3>
            <p className="text-[11px] text-gray-400 mt-0.5">检测到以下手写的 SSH 配置，勾选后导入到炼境统一管理</p>
          </div>
          <button onClick={onClose} className="text-gray-400 hover:text-gray-600 text-lg">x</button>
        </div>

        {/* 列表 */}
        <div className="flex-1 overflow-y-auto px-6 py-3">
          {loading ? (
            <p className="text-xs text-gray-400 text-center py-8">解析中…</p>
          ) : entries.length === 0 ? (
            <p className="text-xs text-gray-400 text-center py-8">未检测到可导入的 SSH 配置条目</p>
          ) : (
            <div className="space-y-1">
              {/* 全选 */}
              <label className="flex items-center gap-2 py-1.5 px-2 rounded hover:bg-gray-50 cursor-pointer">
                <input
                  type="checkbox"
                  checked={selected.size === entries.length}
                  onChange={toggleAll}
                  className="rounded border-gray-300"
                />
                <span className="text-[11px] text-gray-500 font-medium">全选 / 取消全选</span>
              </label>

              {entries.map((entry, idx) => (
                <label
                  key={idx}
                  className={`flex items-center gap-3 py-2.5 px-3 rounded-lg border cursor-pointer transition-colors ${
                    selected.has(idx) ? "border-blue-200 bg-blue-50/50" : "border-gray-100 hover:bg-gray-50"
                  }`}
                >
                  <input
                    type="checkbox"
                    checked={selected.has(idx)}
                    onChange={() => toggleSelect(idx)}
                    className="rounded border-gray-300"
                  />
                  <div className="flex-1 min-w-0">
                    <div className="flex items-center gap-2">
                      <span className="text-xs font-semibold text-gray-800">{entry.host_alias}</span>
                      <span className="text-[11px] font-mono text-gray-400">{entry.hostname}</span>
                    </div>
                    <div className="flex items-center gap-3 mt-0.5 text-[10px] text-gray-400">
                      {entry.user && <span>User: {entry.user}</span>}
                      {entry.port && entry.port !== "22" && <span>Port: {entry.port}</span>}
                      {entry.identity_file && <span className="truncate max-w-[200px]">Key: {entry.identity_file}</span>}
                    </div>
                  </div>
                </label>
              ))}
            </div>
          )}
        </div>

        {/* 底部操作 */}
        <div className="flex items-center justify-between px-6 py-3 border-t border-gray-100 bg-gray-50/50">
          <p className="text-[11px] text-gray-400">
            导入后原 SSH Config 手写条目将由炼境接管
          </p>
          <div className="flex gap-2">
            <button onClick={onClose}
              className="px-3 py-1.5 rounded-md text-xs border border-gray-200 text-gray-500 hover:bg-gray-50 transition-colors">
              取消
            </button>
            <button onClick={handleImport} disabled={selected.size === 0 || importing}
              className="px-4 py-1.5 rounded-md text-xs font-medium bg-blue-600 text-white hover:bg-blue-700 transition-colors disabled:opacity-40">
              {importing ? "导入中…" : `导入 ${selected.size} 条`}
            </button>
          </div>
        </div>
      </div>
    </div>
  );
}

// ── 主面板 ──────────────────────────────────────────────────────────────────

export function ServerManagerPanel() {
  const qc = useQueryClient();
  const [showForm, setShowForm] = useState(false);
  const [showImport, setShowImport] = useState(false);
  const [editingServer, setEditingServer] = useState<Server | null>(null);
  const [sshKeyPath, setSshKeyPath] = useState("");

  // 从 settings 读取全局 SSH 密钥路径
  const { data: settings } = useQuery({
    queryKey: ["settings"],
    queryFn: () => getSettings(),
  });

  useEffect(() => {
    if (settings?.ssh_key_path) {
      setSshKeyPath(settings.ssh_key_path);
    }
  }, [settings]);

  const handleKeyPathChange = async (path: string) => {
    setSshKeyPath(path);
    try {
      await updateSettings({ ssh_key_path: path });
      qc.invalidateQueries({ queryKey: ["settings"] });
    } catch { /* ignore */ }
  };

  const { data: servers = [] } = useQuery({
    queryKey: ["servers"],
    queryFn: getServers,
  });

  const addMut = useMutation({
    mutationFn: (input: SaveServerInput) => addServer(input),
    onSuccess: () => { qc.invalidateQueries({ queryKey: ["servers"] }); setShowForm(false); },
  });

  const editMut = useMutation({
    mutationFn: ({ id, input }: { id: string; input: SaveServerInput }) => editServer(id, input),
    onSuccess: () => {
      qc.invalidateQueries({ queryKey: ["servers"] });
      setEditingServer(null);
    },
  });

  const deleteMut = useMutation({
    mutationFn: (id: string) => deleteServer(id),
    onSuccess: () => qc.invalidateQueries({ queryKey: ["servers"] }),
  });

  return (
    <div className="w-full px-8 py-8 space-y-4 pb-16">
      {/* SSH 密钥配置 */}
      <SshKeySetup keyPath={sshKeyPath} onKeyPathChange={handleKeyPathChange} />

      {/* 顶部操作栏 */}
      <div className="flex items-center justify-between">
        <div className="flex items-center gap-2">
          <h2 className="text-sm font-bold text-gray-700">服务器管理</h2>
          <span className="text-xs text-gray-400 bg-gray-100 rounded-full px-2 py-0.5">
            {servers.length} 台
          </span>
        </div>
        {!showForm && !editingServer && (
          <div className="flex gap-2">
            <button onClick={() => setShowImport(true)}
              className="px-3 py-1.5 rounded-md text-xs font-medium border border-gray-300 text-gray-600 hover:bg-gray-50 transition-colors">
              从 SSH Config 导入
            </button>
            <button onClick={() => setShowForm(true)}
              className="px-3 py-1.5 rounded-md text-xs font-medium border border-blue-300 bg-blue-50 text-blue-600 hover:bg-blue-100 transition-colors">
              + 添加服务器
            </button>
          </div>
        )}
      </div>

      {/* 导入弹窗 */}
      {showImport && (
        <ImportSshConfigModal
          onClose={() => setShowImport(false)}
          onImported={() => qc.invalidateQueries({ queryKey: ["servers"] })}
        />
      )}

      {/* 新增表单 */}
      {showForm && (
        <ServerForm
          onSave={(input) => addMut.mutate(input)}
          onCancel={() => setShowForm(false)}
          saving={addMut.isPending}
        />
      )}

      {/* 服务器列表 */}
      {servers.length === 0 && !showForm && (
        <div className="text-center py-24 text-gray-400">
          <p className="text-4xl mb-4">🖥️</p>
          <p className="text-sm">还没有服务器，点击上方「添加服务器」或「从 SSH Config 导入」</p>
          <p className="text-xs text-gray-300 mt-1">服务器信息可被多个项目共享关联</p>
        </div>
      )}

      {servers.map((s) =>
        editingServer?.id === s.id ? (
          <ServerForm
            key={s.id}
            initial={s}
            onSave={(input) => editMut.mutate({ id: s.id, input })}
            onCancel={() => setEditingServer(null)}
            saving={editMut.isPending}
          />
        ) : (
          <ServerCard
            key={s.id}
            server={s}
            globalKeyPath={sshKeyPath}
            onEdit={() => setEditingServer(s)}
            onDelete={() => deleteMut.mutate(s.id)}
          />
        )
      )}
    </div>
  );
}
