import { useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import {
  ArrowUpDown,
  Check,
  ChevronsDownUp,
  ChevronsUpDown,
  Download,
  Filter,
  FolderPlus,
  Group,
  ListChecks,
  MoreHorizontal,
  Plus,
  RefreshCw,
  Search,
  Server,
  Upload,
  X,
} from "lucide-react";
import { toast } from "sonner";
import { SidebarTree, isFolder } from "@/sidebar/SidebarTree";
import { HostManager } from "@/sidebar/HostManager";
import { HostShareModal } from "@/sidebar/HostShareModal";
import { HostExportDialog } from "@/sidebar/HostExportDialog";
import { ProxmoxDiscoverDialog } from "@/components/proxmox/ProxmoxDiscoverDialog";
import { Button } from "@/components/button";
import {
  DropdownMenu,
  DropdownMenuCheckboxItem,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuSub,
  DropdownMenuSubContent,
  DropdownMenuSubTrigger,
  DropdownMenuTrigger,
} from "@/components/dropdown-menu";
import {
  getSSHHosts,
  bulkImportSSHHosts,
  importSSHConfigHosts,
} from "@/main-axios";
import type { SSHHostWithStatus } from "@/main-axios";
import type { Host, HostFolder, TabType } from "@/types/ui-types";
import {
  resolveHostSortPreferences,
  sortHostTree,
  type SortKey,
} from "@/sidebar/host-sort";

type FilterState = {
  status: ("online" | "offline" | "pinned")[];
  authType: ("password" | "key" | "credential" | "none" | "opkssh")[];
  protocol: ("ssh" | "rdp" | "vnc" | "telnet")[];
  features: ("terminal" | "fileManager" | "tunnel" | "docker")[];
  tags: string[];
};

const DEFAULT_FILTERS: FilterState = {
  status: [],
  authType: [],
  protocol: [],
  features: [],
  tags: [],
};

type GroupKey = "folder" | "tag" | "status" | "protocol" | "auth";

function flattenHosts(folder: HostFolder): Host[] {
  const out: Host[] = [];
  for (const child of folder.children) {
    if (isFolder(child)) out.push(...flattenHosts(child));
    else out.push(child);
  }
  return out;
}

function hostGroupNames(host: Host, key: GroupKey): string[] {
  switch (key) {
    case "tag":
      return host.tags && host.tags.length > 0 ? host.tags : ["__none__"];
    case "status":
      return [host.online ? "online" : "offline"];
    case "protocol": {
      const protos: string[] = [];
      if (host.enableSsh) protos.push("ssh");
      if (host.enableRdp) protos.push("rdp");
      if (host.enableVnc) protos.push("vnc");
      if (host.enableTelnet) protos.push("telnet");
      return protos.length > 0 ? protos : ["__none__"];
    }
    case "auth":
      return [host.authType || "none"];
    default:
      return ["__none__"];
  }
}

function groupHosts(
  tree: HostFolder,
  key: GroupKey,
  labelFor: (key: GroupKey, group: string) => string,
): HostFolder {
  if (key === "folder") return tree;
  const hosts = flattenHosts(tree);
  const groups = new Map<string, Host[]>();
  for (const host of hosts) {
    for (const name of hostGroupNames(host, key)) {
      if (!groups.has(name)) groups.set(name, []);
      groups.get(name)!.push(host);
    }
  }
  const children: (Host | HostFolder)[] = [...groups.entries()]
    .sort((a, b) => labelFor(key, a[0]).localeCompare(labelFor(key, b[0])))
    .map(([group, members]) => ({
      name: labelFor(key, group),
      path: `__group__:${key}:${group}`,
      children: members,
    }));
  return { name: "root", children };
}

function hostPassesFilters(host: Host, filters: FilterState): boolean {
  if (filters.status.length > 0) {
    const ok =
      (filters.status.includes("online") && host.online) ||
      (filters.status.includes("offline") && !host.online) ||
      (filters.status.includes("pinned") && !!host.pin);
    if (!ok) return false;
  }
  if (filters.authType.length > 0) {
    if (
      !filters.authType.includes(
        host.authType as FilterState["authType"][number],
      )
    )
      return false;
  }
  if (filters.protocol.length > 0) {
    const ok =
      (filters.protocol.includes("ssh") && host.enableSsh) ||
      (filters.protocol.includes("rdp") && host.enableRdp) ||
      (filters.protocol.includes("vnc") && host.enableVnc) ||
      (filters.protocol.includes("telnet") && host.enableTelnet);
    if (!ok) return false;
  }
  if (filters.features.length > 0) {
    const ok =
      (filters.features.includes("terminal") && host.enableTerminal) ||
      (filters.features.includes("fileManager") && host.enableFileManager) ||
      (filters.features.includes("tunnel") && host.enableTunnel) ||
      (filters.features.includes("docker") && host.enableDocker);
    if (!ok) return false;
  }
  if (filters.tags.length > 0) {
    const ok = filters.tags.some((tag) => host.tags?.includes(tag));
    if (!ok) return false;
  }
  return true;
}

function applyFilters(folder: HostFolder, filters: FilterState): HostFolder {
  const active = Object.values(filters).some((arr) => arr.length > 0);
  if (!active) return folder;

  const filteredChildren = folder.children
    .map((child) => {
      if (isFolder(child)) return applyFilters(child, filters);
      return hostPassesFilters(child, filters) ? child : null;
    })
    .filter((child): child is Host | HostFolder => {
      if (child === null) return false;
      if (isFolder(child)) return child.children.length > 0;
      return true;
    });
  return { ...folder, children: filteredChildren };
}

export function HostsPanel({
  onOpenTab,
  onEditHost,
  hostTree,
  loading,
  onEditingChange,
  active = true,
}: {
  onOpenTab: (host: Host, type: TabType) => void;
  onEditHost: (host: Host) => void;
  hostTree?: HostFolder;
  loading?: boolean;
  onEditingChange?: (editing: boolean) => void;
  active?: boolean;
}) {
  const { t } = useTranslation();
  const [hostSearch, setHostSearch] = useState("");
  const [managerEditing, setManagerEditing] = useState(false);
  const [selectionMode, setSelectionMode] = useState(false);
  const [refreshing, setRefreshing] = useState(false);
  const [rawHosts, setRawHosts] = useState<SSHHostWithStatus[]>([]);
  const [shareModalHost, setShareModalHost] = useState<Host | null>(null);
  const [exportDialogOpen, setExportDialogOpen] = useState(false);
  const [exportPreselection, setExportPreselection] = useState<Set<string>>(
    new Set(),
  );
  const [proxmoxDialogOpen, setProxmoxDialogOpen] = useState(false);
  const [proxmoxHostId, setProxmoxHostId] = useState<number | undefined>(
    undefined,
  );
  const [proxmoxDefaultCredentialId, setProxmoxDefaultCredentialId] = useState<
    number | null
  >(null);
  const [proxmoxDefaultAuthType, setProxmoxDefaultAuthType] = useState<
    string | undefined
  >(undefined);
  const [proxmoxDefaultUsername, setProxmoxDefaultUsername] = useState<
    string | undefined
  >(undefined);
  const [sortKey, setSortKey] = useState<SortKey>(() => {
    return resolveHostSortPreferences(
      localStorage.getItem("hostSortKey"),
      localStorage.getItem("hostPinnedFirst"),
    ).sortKey;
  });
  const [pinnedFirst, setPinnedFirst] = useState(() => {
    return resolveHostSortPreferences(
      localStorage.getItem("hostSortKey"),
      localStorage.getItem("hostPinnedFirst"),
    ).pinnedFirst;
  });
  const [groupKey, setGroupKey] = useState<GroupKey>(
    () => (localStorage.getItem("hostGroupKey") as GroupKey) ?? "folder",
  );
  const [filterState, setFilterState] = useState<FilterState>(() => {
    try {
      const saved = localStorage.getItem("hostFilterState");
      return saved ? (JSON.parse(saved) as FilterState) : DEFAULT_FILTERS;
    } catch {
      return DEFAULT_FILTERS;
    }
  });
  const filterActive = Object.values(filterState).some((arr) => arr.length > 0);
  const fileInputRef = useRef<HTMLInputElement>(null);
  const sshConfigInputRef = useRef<HTMLInputElement>(null);
  const importOverwriteRef = useRef(false);
  const allTags = [...new Set(rawHosts.flatMap((h) => h.tags ?? []))];

  function handleSortChange(key: SortKey) {
    setSortKey(key);
    localStorage.setItem("hostSortKey", key);
  }

  function handlePinnedFirstChange(enabled: boolean) {
    setPinnedFirst(enabled);
    localStorage.setItem("hostPinnedFirst", String(enabled));
  }

  function handleGroupChange(key: GroupKey) {
    setGroupKey(key);
    localStorage.setItem("hostGroupKey", key);
  }

  function groupLabel(key: GroupKey, group: string): string {
    if (group === "__none__") return t("hosts.groupUngrouped");
    if (key === "status")
      return group === "online"
        ? t("hosts.filterOnline")
        : t("hosts.filterOffline");
    if (key === "protocol") return group.toUpperCase();
    if (key === "auth")
      return t(
        `hosts.filterAuth${group.charAt(0).toUpperCase() + group.slice(1)}`,
      );
    return group;
  }

  function handleFilterToggle<K extends keyof FilterState>(
    group: K,
    value: FilterState[K][number],
  ) {
    setFilterState((prev) => {
      const arr = prev[group] as string[];
      const next = arr.includes(value as string)
        ? arr.filter((v) => v !== value)
        : [...arr, value as string];
      const updated = { ...prev, [group]: next };
      localStorage.setItem("hostFilterState", JSON.stringify(updated));
      return updated as FilterState;
    });
  }

  function handleFilterClear() {
    setFilterState(DEFAULT_FILTERS);
    localStorage.setItem("hostFilterState", JSON.stringify(DEFAULT_FILTERS));
  }

  useEffect(() => {
    let cancelled = false;
    const load = () => {
      getSSHHosts()
        .then((hosts) => {
          if (!cancelled) setRawHosts(hosts);
        })
        .catch(() => {});
    };
    load();
    const onChanged = () => load();
    window.addEventListener("ssh-hosts:changed", onChanged);
    window.addEventListener("hosts:refresh", onChanged);
    window.addEventListener("termix:hosts-changed", onChanged);
    return () => {
      cancelled = true;
      window.removeEventListener("ssh-hosts:changed", onChanged);
      window.removeEventListener("hosts:refresh", onChanged);
      window.removeEventListener("termix:hosts-changed", onChanged);
    };
  }, []);

  function handleEditingChange(editing: boolean) {
    setManagerEditing(editing);
    onEditingChange?.(editing);
  }

  function toggleSelectionMode() {
    setSelectionMode((v) => !v);
  }

  async function handleRefresh() {
    setRefreshing(true);
    try {
      const hosts = await getSSHHosts();
      setRawHosts(hosts);
      window.dispatchEvent(new CustomEvent("termix:hosts-changed"));
    } catch {
      // best-effort
    } finally {
      setRefreshing(false);
    }
  }

  function handleDownloadSample() {
    const sample = JSON.stringify(
      {
        hosts: [
          {
            name: "Web Server (Production)",
            ip: "192.168.1.100",
            username: "admin",
            authType: "password",
            password: "your_secure_password_here",
            folder: "Production",
            tags: ["web", "production", "nginx"],
            pin: true,
            notes: "Main production web server running Nginx",
            enableSsh: true,
            enableRdp: false,
            enableVnc: false,
            enableTelnet: false,
            sshPort: 22,
            enableTerminal: true,
            enableTunnel: false,
            enableFileManager: true,
            enableDocker: false,
            defaultPath: "/var/www",
          },
          {
            name: "Database Server",
            ip: "192.168.1.101",
            username: "dbadmin",
            authType: "key",
            key: "-----BEGIN OPENSSH PRIVATE KEY-----\nYour SSH private key content here\n-----END OPENSSH PRIVATE KEY-----",
            keyPassword: "optional_key_passphrase",
            keyType: "ssh-ed25519",
            folder: "Production",
            tags: ["database", "production", "postgresql"],
            enableSsh: true,
            enableRdp: false,
            enableVnc: false,
            enableTelnet: false,
            sshPort: 22,
            enableTerminal: true,
            enableTunnel: true,
            enableFileManager: false,
            enableDocker: false,
          },
        ],
      },
      null,
      2,
    );
    const blob = new Blob([sample], { type: "application/json" });
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url;
    a.download = "termix-hosts-sample.json";
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
    URL.revokeObjectURL(url);
  }

  return (
    <div className="relative flex flex-col flex-1 min-h-0 overflow-hidden">
      {!managerEditing && (
        <div className="flex flex-col px-2 py-1.5 shrink-0 border-b border-border/60 gap-1.5">
          <div className="flex items-center gap-2 px-2.5 h-7 bg-muted/60 border border-border/60 rounded-sm">
            <Search className="size-3 text-muted-foreground/60 shrink-0" />
            <input
              value={hostSearch}
              onChange={(e) => setHostSearch(e.target.value)}
              placeholder={t("hosts.searchHosts")}
              className="flex-1 text-xs bg-transparent outline-none placeholder:text-muted-foreground/50 text-foreground min-w-0"
            />
            {hostSearch && (
              <button
                onClick={() => setHostSearch("")}
                className="text-muted-foreground/60 hover:text-muted-foreground transition-colors"
              >
                <X className="size-3" />
              </button>
            )}
          </div>

          <input
            ref={fileInputRef}
            type="file"
            accept=".json"
            className="hidden"
            onChange={async (e) => {
              const file = e.target.files?.[0];
              if (!file) return;
              e.target.value = "";
              try {
                const text = await file.text();
                const parsed = JSON.parse(text);
                const hostsArray = Array.isArray(parsed)
                  ? parsed
                  : (parsed.hosts ?? []);
                const credentialsArray =
                  !Array.isArray(parsed) && Array.isArray(parsed.credentials)
                    ? parsed.credentials
                    : undefined;
                if (!Array.isArray(hostsArray) || hostsArray.length === 0) {
                  toast.error("No hosts found in file");
                  return;
                }
                if (hostsArray.length > 100) {
                  toast.error("Cannot import more than 100 hosts at once");
                  return;
                }
                const normalized = hostsArray.map(
                  (h: Record<string, unknown>) => ({
                    ...h,
                    port: h.port ?? h.sshPort ?? 22,
                    enableSsh: h.enableSsh ?? h.connectionType === "ssh",
                    enableRdp: h.enableRdp ?? h.connectionType === "rdp",
                    enableVnc: h.enableVnc ?? h.connectionType === "vnc",
                    enableTelnet:
                      h.enableTelnet ?? h.connectionType === "telnet",
                  }),
                );
                const result = await bulkImportSSHHosts(
                  normalized,
                  importOverwriteRef.current,
                  credentialsArray,
                );
                const hosts = await getSSHHosts();
                setRawHosts(hosts);
                window.dispatchEvent(new CustomEvent("termix:hosts-changed"));
                const msg = [
                  result.success ? `${result.success} imported` : null,
                  result.updated ? `${result.updated} updated` : null,
                  result.failed ? `${result.failed} failed` : null,
                ]
                  .filter(Boolean)
                  .join(", ");
                toast.success(`Import complete: ${msg}`);
              } catch (err: unknown) {
                toast.error(
                  err instanceof Error ? err.message : "Failed to import hosts",
                );
              }
            }}
          />

          <input
            ref={sshConfigInputRef}
            type="file"
            accept=".conf,.config,*"
            className="hidden"
            onChange={async (e) => {
              const file = e.target.files?.[0];
              if (!file) return;
              e.target.value = "";
              try {
                const text = await file.text();
                const result = await importSSHConfigHosts(
                  text,
                  importOverwriteRef.current,
                );
                const hosts = await getSSHHosts();
                setRawHosts(hosts);
                window.dispatchEvent(new CustomEvent("termix:hosts-changed"));
                const msg = [
                  result.success ? `${result.success} imported` : null,
                  result.updated ? `${result.updated} updated` : null,
                  result.failed ? `${result.failed} failed` : null,
                ]
                  .filter(Boolean)
                  .join(", ");
                toast.success(`${t("hosts.importSSHConfig")}: ${msg}`);
              } catch (err: unknown) {
                toast.error(
                  err instanceof Error
                    ? err.message
                    : "Failed to import SSH config",
                );
              }
            }}
          />

          <div className="flex flex-wrap items-center gap-1">
            <Button
              variant="ghost"
              size="icon"
              className="size-7 text-muted-foreground hover:text-foreground"
              title={t("hosts.refreshBtn2")}
              onClick={handleRefresh}
              disabled={refreshing}
            >
              <RefreshCw
                className={`size-3.5 ${refreshing ? "animate-spin" : ""}`}
              />
            </Button>
            <DropdownMenu>
              <DropdownMenuTrigger asChild>
                <Button
                  variant="ghost"
                  size="icon"
                  className="size-7 text-muted-foreground hover:text-foreground"
                  title={t("hosts.importExportBtn")}
                >
                  <Upload className="size-3.5" />
                </Button>
              </DropdownMenuTrigger>
              <DropdownMenuContent align="start" className="text-xs">
                <DropdownMenuItem
                  onClick={() => {
                    importOverwriteRef.current = false;
                    fileInputRef.current?.click();
                  }}
                >
                  <Upload className="size-3.5 mr-2" />
                  {t("hosts.importSkipExisting")}
                </DropdownMenuItem>
                <DropdownMenuItem
                  onClick={() => {
                    importOverwriteRef.current = true;
                    fileInputRef.current?.click();
                  }}
                >
                  <Upload className="size-3.5 mr-2" />
                  {t("hosts.importOverwrite")}
                </DropdownMenuItem>
                <DropdownMenuItem
                  onClick={() => {
                    importOverwriteRef.current = false;
                    sshConfigInputRef.current?.click();
                  }}
                >
                  <Upload className="size-3.5 mr-2" />
                  {t("hosts.importSSHConfig")}
                </DropdownMenuItem>
                <DropdownMenuItem
                  onClick={() => {
                    setProxmoxHostId(undefined);
                    setProxmoxDialogOpen(true);
                  }}
                  disabled={
                    !rawHosts.some(
                      (h) => !isFolder(h) && (h as any).enableProxmox,
                    )
                  }
                >
                  <Server className="size-3.5 mr-2" />
                  {t("hosts.proxmoxImportTitle")}
                </DropdownMenuItem>
                <DropdownMenuSeparator />
                <DropdownMenuItem
                  onClick={() => {
                    setExportPreselection(new Set());
                    setExportDialogOpen(true);
                  }}
                  disabled={rawHosts.length === 0}
                >
                  <Download className="size-3.5 mr-2" />
                  {t("hosts.export.menuItem")}
                </DropdownMenuItem>
                <DropdownMenuItem onClick={handleDownloadSample}>
                  <Download className="size-3.5 mr-2" />
                  {t("hosts.downloadSample")}
                </DropdownMenuItem>
              </DropdownMenuContent>
            </DropdownMenu>
            <button
              title={
                selectionMode
                  ? t("hosts.exitSelectionTitle")
                  : t("hosts.selectHosts")
              }
              onClick={toggleSelectionMode}
              className={`flex items-center justify-center size-7 rounded-sm shrink-0 transition-colors ${selectionMode ? "text-accent-brand bg-accent-brand/10 border border-accent-brand/30" : "text-muted-foreground/60 hover:text-foreground hover:bg-muted/60 border border-transparent"}`}
            >
              <ListChecks className="size-3.5" />
            </button>
            <DropdownMenu>
              <DropdownMenuTrigger asChild>
                <Button
                  variant="ghost"
                  size="icon"
                  className={`size-7 ${sortKey !== "default" || pinnedFirst ? "text-accent-brand" : "text-muted-foreground hover:text-foreground"}`}
                  title={t("hosts.sortHosts")}
                >
                  <ArrowUpDown className="size-3.5" />
                </Button>
              </DropdownMenuTrigger>
              <DropdownMenuContent
                align="start"
                className="text-xs min-w-[160px]"
              >
                <DropdownMenuItem
                  onClick={() => handleSortChange("default")}
                  className="flex items-center gap-1.5"
                >
                  {sortKey === "default" ? (
                    <Check className="size-3 shrink-0 text-accent-brand" />
                  ) : (
                    <span className="size-3 shrink-0 inline-block" />
                  )}
                  {t("hosts.sortDefault")}
                </DropdownMenuItem>
                <DropdownMenuSeparator />
                {(["name-asc", "name-desc"] as const).map((key) => (
                  <DropdownMenuItem
                    key={key}
                    onClick={() => handleSortChange(key)}
                    className="flex items-center gap-1.5"
                  >
                    {sortKey === key ? (
                      <Check className="size-3 shrink-0 text-accent-brand" />
                    ) : (
                      <span className="size-3 shrink-0 inline-block" />
                    )}
                    {t(
                      `hosts.sort${key === "name-asc" ? "NameAsc" : "NameDesc"}`,
                    )}
                  </DropdownMenuItem>
                ))}
                <DropdownMenuSeparator />
                {(["ip-asc", "ip-desc"] as const).map((key) => (
                  <DropdownMenuItem
                    key={key}
                    onClick={() => handleSortChange(key)}
                    className="flex items-center gap-1.5"
                  >
                    {sortKey === key ? (
                      <Check className="size-3 shrink-0 text-accent-brand" />
                    ) : (
                      <span className="size-3 shrink-0 inline-block" />
                    )}
                    {t(`hosts.sort${key === "ip-asc" ? "IpAsc" : "IpDesc"}`)}
                  </DropdownMenuItem>
                ))}
                <DropdownMenuSeparator />
                {(["status-online", "status-offline"] as const).map((key) => (
                  <DropdownMenuItem
                    key={key}
                    onClick={() => handleSortChange(key)}
                    className="flex items-center gap-1.5"
                  >
                    {sortKey === key ? (
                      <Check className="size-3 shrink-0 text-accent-brand" />
                    ) : (
                      <span className="size-3 shrink-0 inline-block" />
                    )}
                    {t(
                      key === "status-online"
                        ? "hosts.sortOnlineFirst"
                        : "hosts.sortOfflineFirst",
                    )}
                  </DropdownMenuItem>
                ))}
                <DropdownMenuSeparator />
                <DropdownMenuCheckboxItem
                  checked={pinnedFirst}
                  onCheckedChange={handlePinnedFirstChange}
                  onSelect={(event) => event.preventDefault()}
                >
                  {t("hosts.sortPinnedFirst")}
                </DropdownMenuCheckboxItem>
              </DropdownMenuContent>
            </DropdownMenu>
            <DropdownMenu>
              <DropdownMenuTrigger asChild>
                <Button
                  variant="ghost"
                  size="icon"
                  className={`size-7 ${filterActive ? "text-accent-brand" : "text-muted-foreground hover:text-foreground"}`}
                  title={t("hosts.filterHosts")}
                >
                  <Filter className="size-3.5" />
                </Button>
              </DropdownMenuTrigger>
              <DropdownMenuContent
                align="start"
                className="text-xs min-w-[180px]"
              >
                {filterActive && (
                  <>
                    <DropdownMenuItem
                      onClick={handleFilterClear}
                      className="flex items-center gap-1.5 text-accent-brand"
                    >
                      <X className="size-3 shrink-0" />
                      {t("hosts.filterClearAll")}
                    </DropdownMenuItem>
                    <DropdownMenuSeparator />
                  </>
                )}
                <DropdownMenuLabel>
                  {t("hosts.filterStatusGroup")}
                </DropdownMenuLabel>
                {(["online", "offline", "pinned"] as const).map((val) => (
                  <DropdownMenuCheckboxItem
                    key={val}
                    checked={filterState.status.includes(val)}
                    onCheckedChange={() => handleFilterToggle("status", val)}
                    onSelect={(e) => e.preventDefault()}
                  >
                    {t(
                      `hosts.filter${val.charAt(0).toUpperCase() + val.slice(1)}`,
                    )}
                  </DropdownMenuCheckboxItem>
                ))}
                <DropdownMenuSeparator />
                <DropdownMenuLabel>
                  {t("hosts.filterAuthGroup")}
                </DropdownMenuLabel>
                {(
                  ["password", "key", "credential", "none", "opkssh"] as const
                ).map((val) => (
                  <DropdownMenuCheckboxItem
                    key={val}
                    checked={filterState.authType.includes(val)}
                    onCheckedChange={() => handleFilterToggle("authType", val)}
                    onSelect={(e) => e.preventDefault()}
                  >
                    {t(
                      `hosts.filterAuth${val.charAt(0).toUpperCase() + val.slice(1)}`,
                    )}
                  </DropdownMenuCheckboxItem>
                ))}
                <DropdownMenuSeparator />
                <DropdownMenuLabel>
                  {t("hosts.filterProtocolGroup")}
                </DropdownMenuLabel>
                {(
                  [
                    ["ssh", "Ssh"],
                    ["rdp", "Rdp"],
                    ["vnc", "Vnc"],
                    ["telnet", "Telnet"],
                  ] as const
                ).map(([val, key]) => (
                  <DropdownMenuCheckboxItem
                    key={val}
                    checked={filterState.protocol.includes(val)}
                    onCheckedChange={() => handleFilterToggle("protocol", val)}
                    onSelect={(e) => e.preventDefault()}
                  >
                    {t(`hosts.filterProtocol${key}`)}
                  </DropdownMenuCheckboxItem>
                ))}
                <DropdownMenuSeparator />
                <DropdownMenuLabel>
                  {t("hosts.filterFeaturesGroup")}
                </DropdownMenuLabel>
                {(
                  [
                    ["terminal", "Terminal"],
                    ["fileManager", "FileManager"],
                    ["tunnel", "Tunnel"],
                    ["docker", "Docker"],
                  ] as const
                ).map(([val, key]) => (
                  <DropdownMenuCheckboxItem
                    key={val}
                    checked={filterState.features.includes(val)}
                    onCheckedChange={() => handleFilterToggle("features", val)}
                    onSelect={(e) => e.preventDefault()}
                  >
                    {t(`hosts.filterFeature${key}`)}
                  </DropdownMenuCheckboxItem>
                ))}
                {allTags.length > 0 && (
                  <>
                    <DropdownMenuSeparator />
                    <DropdownMenuLabel>
                      {t("hosts.filterTagsGroup")}
                    </DropdownMenuLabel>
                    {allTags.map((tag) => (
                      <DropdownMenuCheckboxItem
                        key={tag}
                        checked={filterState.tags.includes(tag)}
                        onCheckedChange={() => handleFilterToggle("tags", tag)}
                        onSelect={(e) => e.preventDefault()}
                      >
                        {tag}
                      </DropdownMenuCheckboxItem>
                    ))}
                  </>
                )}
              </DropdownMenuContent>
            </DropdownMenu>
            <DropdownMenu>
              <DropdownMenuTrigger asChild>
                <Button
                  variant="ghost"
                  size="icon"
                  className={`size-7 ${groupKey !== "folder" || selectionMode ? "text-accent-brand" : "text-muted-foreground hover:text-foreground"}`}
                  title={t("hosts.moreActions")}
                >
                  <MoreHorizontal className="size-3.5" />
                </Button>
              </DropdownMenuTrigger>
              <DropdownMenuContent
                align="start"
                className="text-xs min-w-[180px]"
              >
                <DropdownMenuSub>
                  <DropdownMenuSubTrigger className="flex items-center gap-2">
                    <Group className="size-3.5 shrink-0" />
                    {t("hosts.groupBy")}
                    {groupKey !== "folder" && (
                      <span className="ml-auto text-accent-brand">
                        {t(
                          `hosts.GroupBy${groupKey.charAt(0).toUpperCase() + groupKey.slice(1)}`,
                        )}
                      </span>
                    )}
                  </DropdownMenuSubTrigger>
                  <DropdownMenuSubContent className="text-xs min-w-[150px]">
                    {(
                      [
                        ["folder", "GroupByFolder"],
                        ["tag", "GroupByTag"],
                        ["status", "GroupByStatus"],
                        ["protocol", "GroupByProtocol"],
                        ["auth", "GroupByAuth"],
                      ] as const
                    ).map(([key, label]) => (
                      <DropdownMenuItem
                        key={key}
                        onClick={() => handleGroupChange(key)}
                        className="flex items-center gap-1.5"
                      >
                        {groupKey === key ? (
                          <Check className="size-3 shrink-0 text-accent-brand" />
                        ) : (
                          <span className="size-3 shrink-0 inline-block" />
                        )}
                        {t(`hosts.${label}`)}
                      </DropdownMenuItem>
                    ))}
                  </DropdownMenuSubContent>
                </DropdownMenuSub>
                <DropdownMenuSeparator />
                <DropdownMenuItem
                  onClick={() =>
                    window.dispatchEvent(new CustomEvent("hosts:create-folder"))
                  }
                >
                  <FolderPlus className="size-3.5 mr-2" />
                  {t("hosts.newFolder")}
                </DropdownMenuItem>
                <DropdownMenuItem
                  onClick={() =>
                    window.dispatchEvent(new CustomEvent("hosts:expand-all"))
                  }
                >
                  <ChevronsUpDown className="size-3.5 mr-2" />
                  {t("hosts.expandAll")}
                </DropdownMenuItem>
                <DropdownMenuItem
                  onClick={() =>
                    window.dispatchEvent(new CustomEvent("hosts:collapse-all"))
                  }
                >
                  <ChevronsDownUp className="size-3.5 mr-2" />
                  {t("hosts.collapseAll")}
                </DropdownMenuItem>
                <DropdownMenuSeparator />
                <DropdownMenuItem
                  onClick={toggleSelectionMode}
                  className={selectionMode ? "text-accent-brand" : ""}
                >
                  <ListChecks className="size-3.5 mr-2" />
                  {selectionMode
                    ? t("hosts.exitSelectionTitle")
                    : t("hosts.selectHosts")}
                </DropdownMenuItem>
                <DropdownMenuSub>
                  <DropdownMenuSubTrigger className="flex items-center gap-2">
                    <Upload className="size-3.5 shrink-0" />
                    {t("hosts.importExportBtn")}
                  </DropdownMenuSubTrigger>
                  <DropdownMenuSubContent className="text-xs min-w-[170px]">
                    <DropdownMenuItem
                      onClick={() => {
                        importOverwriteRef.current = false;
                        fileInputRef.current?.click();
                      }}
                    >
                      <Upload className="size-3.5 mr-2" />
                      {t("hosts.importSkipExisting")}
                    </DropdownMenuItem>
                    <DropdownMenuItem
                      onClick={() => {
                        importOverwriteRef.current = true;
                        fileInputRef.current?.click();
                      }}
                    >
                      <Upload className="size-3.5 mr-2" />
                      {t("hosts.importOverwrite")}
                    </DropdownMenuItem>
                    <DropdownMenuItem
                      onClick={() => {
                        importOverwriteRef.current = false;
                        sshConfigInputRef.current?.click();
                      }}
                    >
                      <Upload className="size-3.5 mr-2" />
                      {t("hosts.importSSHConfig")}
                    </DropdownMenuItem>
                    <DropdownMenuItem
                      onClick={() => {
                        setExportPreselection(new Set());
                        setExportDialogOpen(true);
                      }}
                      disabled={rawHosts.length === 0}
                    >
                      <Download className="size-3.5 mr-2" />
                      {t("hosts.export.menuItem")}
                    </DropdownMenuItem>
                    <DropdownMenuItem onClick={handleDownloadSample}>
                      <Download className="size-3.5 mr-2" />
                      {t("hosts.downloadSample")}
                    </DropdownMenuItem>
                  </DropdownMenuSubContent>
                </DropdownMenuSub>
              </DropdownMenuContent>
            </DropdownMenu>
            <button
              onClick={() =>
                window.dispatchEvent(new CustomEvent("host-manager:add-host"))
              }
              title={t("hosts.addHost")}
              className="flex items-center gap-1 h-7 px-2 text-[10px] font-medium text-accent-brand hover:bg-accent-brand/10 border border-accent-brand/30 rounded-sm shrink-0 transition-colors"
            >
              <Plus className="size-3 shrink-0" />
              {t("hosts.addHost")}
            </button>
          </div>
        </div>
      )}

      <div
        className={`flex flex-col flex-1 min-h-0 ${managerEditing ? "hidden" : ""}`}
      >
        <SidebarTree
          children={
            hostTree
              ? groupHosts(
                  applyFilters(
                    sortHostTree(hostTree, sortKey, pinnedFirst),
                    filterState,
                  ),
                  groupKey,
                  groupLabel,
                ).children
              : []
          }
          onOpenTab={onOpenTab}
          onEditHost={onEditHost}
          onShareHost={(host) => setShareModalHost(host)}
          onProxmoxDiscover={(host) => {
            const cfg = host.proxmoxConfig;
            setProxmoxHostId(Number(host.id));
            setProxmoxDefaultCredentialId(cfg?.defaultCredentialId ?? null);
            setProxmoxDefaultAuthType(cfg?.defaultAuthType ?? undefined);
            setProxmoxDefaultUsername(undefined);
            setProxmoxDialogOpen(true);
          }}
          query={hostSearch.trim().toLowerCase()}
          selectionMode={selectionMode}
          onToggleSelectionMode={toggleSelectionMode}
          loading={loading}
          onExportSelected={(ids) => {
            setExportPreselection(new Set(ids));
            setExportDialogOpen(true);
          }}
        />
      </div>

      <div
        className={managerEditing ? "flex flex-col flex-1 min-h-0" : "hidden"}
      >
        <HostManager onEditingChange={handleEditingChange} active={active} />
      </div>

      <HostShareModal
        open={shareModalHost !== null}
        onClose={() => setShareModalHost(null)}
        host={shareModalHost}
      />

      <HostExportDialog
        open={exportDialogOpen}
        onClose={() => setExportDialogOpen(false)}
        hosts={rawHosts}
        preselectedHostIds={exportPreselection}
      />

      <ProxmoxDiscoverDialog
        open={proxmoxDialogOpen}
        onClose={() => {
          setProxmoxDialogOpen(false);
          setProxmoxHostId(undefined);
        }}
        hosts={rawHosts}
        onHostsChanged={setRawHosts}
        preselectedHostId={proxmoxHostId}
        defaultCredentialId={proxmoxDefaultCredentialId}
        defaultAuthType={proxmoxDefaultAuthType}
        defaultUsername={proxmoxDefaultUsername}
      />
    </div>
  );
}
