"use client";

import { type ChangeEvent, type MouseEvent, useCallback, useEffect, useState } from "react";

import OverviewCharts from "@/components/OverviewCharts";

type Lang = "zh" | "en";
type ThemeMode = "dark" | "light";
type TabKey = "overview" | "business" | "modules" | "shellcrash" | "android" | "config";

type LoadAvg = { "1m"?: number; "5m"?: number; "15m"?: number };
type Capacity = { total?: number; free?: number; used?: number; available?: number };
type ProcessEntry = { pm2: string; script: string; label: string };
type ProcessStatusResponse = {
  process_status?: string;
  recent_log?: string;
  recent_error?: string;
  output?: string;
  pm2_output?: string;
  message?: string;
};
type ManagedRoot = {
  root_id: string;
  label: string;
  description: string;
  path: string;
  exists: boolean;
  allow_create: boolean;
  allow_delete: boolean;
  recursive: boolean;
  default_file?: string | null;
  file_count: number;
};
type ManagedFile = { path: string; size: number; mtime: number };
type StackSummary = {
  hostname?: string;
  mdns_host?: string;
  machine?: string;
  kernel?: string;
  ips?: string[];
  dashboard_url?: string;
  control_url?: string;
  quick_links?: Record<string, string>;
};
type ServiceItem = {
  service_id: string;
  label: string;
  description: string;
  available: boolean;
  running: boolean;
  status: string;
  detail?: string;
  url?: string;
  host?: string;
  port?: string;
  message?: string;
};
type SystemSnapshot = {
  cpu_load?: LoadAvg;
  disk?: Capacity;
  memory?: Capacity;
  netdata?: { available?: boolean; version?: string };
};
type HardwareProfile = {
  arch?: string;
  ffmpeg_hwaccels?: string[];
  gpu?: { present?: boolean; driver?: string };
  npu?: { present?: boolean; devices?: string[] };
  recommendation?: {
    video_decoder?: string;
    hdmi_player?: string;
    stability_mode?: string;
  };
};
type AndroidDevice = {
  serial: string;
  state: string;
  usb?: string;
  product?: string;
  model?: string;
  device?: string;
};
type AndroidOverview = {
  serial?: string;
  model?: string;
  brand?: string;
  android_version?: string;
  sdk?: string;
  battery?: string;
  focus?: string;
  resolution?: string;
  rotation?: string;
  screen_state?: string;
};
type AndroidNode = {
  label: string;
  text?: string;
  content_desc?: string;
  resource_id?: string;
  class_name?: string;
  package?: string;
  bounds?: string;
  center_x: number;
  center_y: number;
  clickable?: boolean;
  focusable?: boolean;
  scrollable?: boolean;
  enabled?: boolean;
};
type AndroidPackage = {
  package: string;
  label?: string;
};
type PreviewMode = "tap" | "double_tap" | "long_press";

const TABS: TabKey[] = ["overview", "business", "modules", "shellcrash", "android", "config"];
const SHELLCRASH_ROOT_IDS = new Set(["shellcrash-configs", "shellcrash-yamls", "shellcrash-jsons"]);

const apiBase = () =>
  (typeof process !== "undefined" && process.env.NEXT_PUBLIC_API_URL) || "";

function formatBytes(value?: number) {
  if (!value) return "0 B";
  const units = ["B", "KB", "MB", "GB", "TB"];
  let amount = value;
  let index = 0;
  while (amount >= 1024 && index < units.length - 1) {
    amount /= 1024;
    index += 1;
  }
  return `${amount.toFixed(amount >= 10 || index === 0 ? 0 : 1)} ${units[index]}`;
}

function statusTone(status: string) {
  if (status === "online") return "border-emerald-500/30 bg-emerald-500/10 text-emerald-200";
  if (status === "stopped") return "border-slate-500/30 bg-slate-500/10 text-slate-300";
  if (status === "configured") return "border-violet-500/30 bg-violet-500/10 text-violet-200";
  if (status === "unavailable") return "border-slate-700/30 bg-slate-800/50 text-slate-500";
  if (status === "error") return "border-rose-500/30 bg-rose-500/10 text-rose-200";
  return "border-cyan-500/30 bg-cyan-500/10 text-cyan-200";
}

function isTabKey(value: string | null): value is TabKey {
  return value !== null && (TABS as string[]).includes(value);
}

function pathnameToTab(pathname: string): TabKey | null {
  const normalized = pathname.replace(/\/+$/, "") || "/";
  if (normalized === "/shellcrash") return "shellcrash";
  if (normalized === "/android") return "android";
  return null;
}

function tabPath(tab: TabKey) {
  if (tab === "shellcrash") return "/shellcrash";
  if (tab === "android") return "/android";
  return "/";
}

function parseResolution(resolution?: string) {
  const match = resolution?.match(/(\d+)x(\d+)/);
  if (!match) return null;
  return { width: Number(match[1]), height: Number(match[2]) };
}

function Button({
  children,
  className,
  disabled,
  onClick,
  title,
}: {
  children: React.ReactNode;
  className?: string;
  disabled?: boolean;
  onClick?: () => void;
  title?: string;
}) {
  return (
    <button
      type="button"
      className={`btn-focus rounded-xl px-3 py-2 text-xs font-semibold text-white disabled:cursor-not-allowed disabled:opacity-40 ${className || ""}`}
      disabled={disabled}
      onClick={onClick}
      title={title}
    >
      {children}
    </button>
  );
}

export default function Home() {
  const base = apiBase();
  const [lang, setLang] = useState<Lang>("zh");
  const [theme, setTheme] = useState<ThemeMode>("dark");
  const [tab, setTab] = useState<TabKey>("overview");
  const tr = useCallback((zh: string, en: string) => (lang === "zh" ? zh : en), [lang]);

  const [booting, setBooting] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [toast, setToast] = useState<string | null>(null);
  const [busy, setBusy] = useState<string | null>(null);

  const [entries, setEntries] = useState<ProcessEntry[]>([]);
  const [currentProcess, setCurrentProcess] = useState("");
  const [processStatus, setProcessStatus] = useState("unknown");
  const [recentLog, setRecentLog] = useState("");
  const [recentError, setRecentError] = useState("");

  const [stack, setStack] = useState<StackSummary | null>(null);
  const [services, setServices] = useState<ServiceItem[]>([]);
  const [snapshot, setSnapshot] = useState<SystemSnapshot | null>(null);
  const [hardware, setHardware] = useState<HardwareProfile | null>(null);

  const [roots, setRoots] = useState<ManagedRoot[]>([]);
  const [rootId, setRootId] = useState("");
  const [files, setFiles] = useState<ManagedFile[]>([]);
  const [filePath, setFilePath] = useState("");
  const [fileContent, setFileContent] = useState("");

  const [androidAvailable, setAndroidAvailable] = useState(false);
  const [androidDevices, setAndroidDevices] = useState<AndroidDevice[]>([]);
  const [androidSerial, setAndroidSerial] = useState("");
  const [androidOverview, setAndroidOverview] = useState<AndroidOverview | null>(null);
  const [androidNodes, setAndroidNodes] = useState<AndroidNode[]>([]);
  const [androidPackages, setAndroidPackages] = useState<AndroidPackage[]>([]);
  const [androidPackageQuery, setAndroidPackageQuery] = useState("");
  const [androidText, setAndroidText] = useState("");
  const [androidPackage, setAndroidPackage] = useState("com.zhiliaoapp.musically");
  const [androidUrl, setAndroidUrl] = useState("https://www.tiktok.com");
  const [androidShell, setAndroidShell] = useState("");
  const [androidOutput, setAndroidOutput] = useState("");
  const [shotNonce, setShotNonce] = useState(Date.now());
  const [previewMode, setPreviewMode] = useState<PreviewMode>("tap");
  const [previewPoint, setPreviewPoint] = useState<{ x: number; y: number } | null>(null);
  const [fileImportKey, setFileImportKey] = useState(0);

  const currentRoot = roots.find((item) => item.root_id === rootId) ?? null;
  const shellRoots = roots.filter((item) => SHELLCRASH_ROOT_IDS.has(item.root_id));
  const otherRoots = roots.filter((item) => !SHELLCRASH_ROOT_IDS.has(item.root_id));
  const shellcrashService = services.find((item) => item.service_id === "shellcrash") ?? null;
  const androidService = services.find((item) => item.service_id === "android_panel") ?? null;
  const ql = stack?.quick_links ?? {};
  const rawAndroidPanelUrl =
    ql.ws_scrcpy ||
    (androidService?.host && androidService.port
      ? `http://${androidService.host}:${androidService.port}`
      : stack?.mdns_host
        ? `http://${stack.mdns_host}:5000`
        : "");
  const androidResolution = parseResolution(androidOverview?.resolution);

  const notify = useCallback((message: string) => {
    setToast(message);
    window.setTimeout(() => setToast(null), 2500);
  }, []);

  const fetchJson = useCallback(
    async <T,>(path: string, init?: RequestInit): Promise<T> => {
      const response = await fetch(`${base}${path}`, init);
      const data = (await response.json()) as T & { error?: string };
      if (!response.ok) {
        throw new Error(data.error || `HTTP ${response.status}`);
      }
      return data;
    },
    [base],
  );

  const syncUrl = useCallback((nextTab: TabKey, nextLang: Lang) => {
    const url = new URL(window.location.href);
    url.pathname = tabPath(nextTab);
    if (url.pathname === "/") {
      url.searchParams.set("tab", nextTab);
    } else {
      url.searchParams.delete("tab");
    }
    url.searchParams.set("lang", nextLang);
    window.history.replaceState(null, "", url.toString());
    window.localStorage.setItem("live-console-lang", nextLang);
  }, []);

  const refreshProcess = useCallback(async () => {
    if (!currentProcess) return;
    const data = await fetchJson<ProcessStatusResponse>(
      `/status?process=${encodeURIComponent(currentProcess)}`,
    );
    setProcessStatus(data.process_status || "unknown");
    setRecentLog(data.recent_log || "");
    setRecentError(data.recent_error || "");
  }, [currentProcess, fetchJson]);

  const refreshServices = useCallback(async () => {
    const [serviceData, snapshotData, hardwareData] = await Promise.all([
      fetchJson<{ services?: ServiceItem[] }>("/stack/services"),
      fetchJson<SystemSnapshot>("/system_snapshot"),
      fetchJson<HardwareProfile>("/hardware_profile"),
    ]);
    setServices(serviceData.services || []);
    setSnapshot(snapshotData);
    setHardware(hardwareData);
  }, [fetchJson]);

  const refreshFiles = useCallback(
    async (selectedRoot: string, preferredPath?: string) => {
      if (!selectedRoot) return;
      const data = await fetchJson<{ files?: ManagedFile[] }>(
        `/managed_files?root=${encodeURIComponent(selectedRoot)}`,
      );
      const nextFiles = data.files || [];
      setFiles(nextFiles);
      const expected = preferredPath || filePath;
      if (expected && nextFiles.some((item) => item.path === expected)) {
        setFilePath(expected);
      } else {
        setFilePath(nextFiles[0]?.path || "");
      }
    },
    [fetchJson, filePath],
  );

  const refreshAndroidDevices = useCallback(async () => {
    const data = await fetchJson<{ available?: boolean; devices?: AndroidDevice[] }>("/android/devices");
    const nextDevices = data.devices || [];
    const nextSerial =
      androidSerial && nextDevices.some((item) => item.serial === androidSerial)
        ? androidSerial
        : nextDevices[0]?.serial || "";
    setAndroidAvailable(Boolean(data.available));
    setAndroidDevices(nextDevices);
    setAndroidSerial(nextSerial);
    return nextSerial;
  }, [androidSerial, fetchJson]);

  const refreshAndroidOverview = useCallback(
    async (serial: string) => {
      if (!serial) {
        setAndroidOverview(null);
        return;
      }
      const data = await fetchJson<AndroidOverview>(
        `/android/overview?serial=${encodeURIComponent(serial)}`,
      );
      setAndroidOverview(data);
    },
    [fetchJson],
  );

  const refreshAndroidPackages = useCallback(
    async (serial: string, query = androidPackageQuery) => {
      if (!serial) {
        setAndroidPackages([]);
        return;
      }
      const data = await fetchJson<{ packages?: AndroidPackage[] }>(
        `/android/packages?serial=${encodeURIComponent(serial)}&query=${encodeURIComponent(query)}&limit=60`,
      );
      setAndroidPackages(data.packages || []);
    },
    [androidPackageQuery, fetchJson],
  );

  const refreshAndroidUi = useCallback(
    async (serial: string) => {
      if (!serial) {
        setAndroidNodes([]);
        return;
      }
      const data = await fetchJson<{ nodes?: AndroidNode[] }>(
        `/android/ui?serial=${encodeURIComponent(serial)}&limit=80`,
      );
      setAndroidNodes(data.nodes || []);
    },
    [fetchJson],
  );

  const openManagedFile = useCallback(
    async (nextRoot: string, nextPath: string) => {
      setRootId(nextRoot);
      setFilePath(nextPath);
      await refreshFiles(nextRoot, nextPath);
    },
    [refreshFiles],
  );

  const boot = useCallback(async () => {
    setBooting(true);
    setError(null);
    try {
      const [monitor, info, managed] = await Promise.all([
        fetchJson<{ entries?: ProcessEntry[] }>("/process_monitor"),
        fetchJson<{ stack?: StackSummary }>("/server_info"),
        fetchJson<{ roots?: ManagedRoot[] }>("/managed_roots"),
      ]);
      setEntries(monitor.entries || []);
      setCurrentProcess(monitor.entries?.[0]?.pm2 || "");
      setStack(info.stack || null);
      setRoots(managed.roots || []);
      setRootId(managed.roots?.[0]?.root_id || "");
      await Promise.all([refreshServices(), refreshAndroidDevices()]);
    } catch (reason) {
      setError((reason as Error).message);
    } finally {
      setBooting(false);
    }
  }, [fetchJson, refreshAndroidDevices, refreshServices]);

  useEffect(() => {
    const params = new URLSearchParams(window.location.search);
    const pathTab = pathnameToTab(window.location.pathname);
    const nextTab = params.get("tab");
    const nextLang = params.get("lang");
    const storedLang = window.localStorage.getItem("live-console-lang");
    if (pathTab) setTab(pathTab);
    else if (isTabKey(nextTab)) setTab(nextTab);
    if (nextLang === "zh" || nextLang === "en") setLang(nextLang);
    else if (storedLang === "zh" || storedLang === "en") setLang(storedLang);
    const storedTheme = window.localStorage.getItem("live-console-theme");
    if (storedTheme === "light" || storedTheme === "dark") setTheme(storedTheme);
  }, []);

  useEffect(() => {
    document.documentElement.setAttribute("data-theme", theme);
    window.localStorage.setItem("live-console-theme", theme);
  }, [theme]);

  useEffect(() => {
    syncUrl(tab, lang);
  }, [lang, syncUrl, tab]);

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

  useEffect(() => {
    if (!currentProcess) return;
    void refreshProcess();
    const timer = window.setInterval(() => void refreshProcess(), 1500);
    return () => window.clearInterval(timer);
  }, [currentProcess, refreshProcess]);

  useEffect(() => {
    const visibleRoots = tab === "shellcrash" ? shellRoots : tab === "config" ? otherRoots : roots;
    if (!visibleRoots.length) return;
    if (!visibleRoots.some((item) => item.root_id === rootId)) {
      setRootId(visibleRoots[0].root_id);
      setFilePath("");
    }
  }, [otherRoots, rootId, roots, shellRoots, tab]);

  useEffect(() => {
    if (!rootId) return;
    void refreshFiles(rootId);
  }, [refreshFiles, rootId]);

  useEffect(() => {
    if (!rootId || !filePath) {
      setFileContent("");
      return;
    }
    (async () => {
      try {
        const data = await fetchJson<{ content?: string }>(
          `/managed_file?root=${encodeURIComponent(rootId)}&path=${encodeURIComponent(filePath)}`,
        );
        setFileContent(data.content || "");
      } catch (reason) {
        notify((reason as Error).message);
      }
    })();
  }, [fetchJson, filePath, notify, rootId]);

  useEffect(() => {
    if (tab !== "android") return;
    void (async () => {
      const serial = await refreshAndroidDevices();
      if (serial) {
        await Promise.all([
          refreshAndroidOverview(serial),
          refreshAndroidUi(serial),
          refreshAndroidPackages(serial),
        ]);
        setShotNonce(Date.now());
      }
    })();
  }, [refreshAndroidDevices, refreshAndroidOverview, refreshAndroidPackages, refreshAndroidUi, tab]);

  useEffect(() => {
    if (tab !== "android" || !androidSerial) return;
    const timer = window.setInterval(() => {
      void refreshAndroidOverview(androidSerial);
      setShotNonce(Date.now());
    }, 5000);
    return () => window.clearInterval(timer);
  }, [androidSerial, refreshAndroidOverview, tab]);

  const processAction = async (action: "start" | "restart" | "stop") => {
    if (!currentProcess) return;
    setBusy(`process:${action}`);
    try {
      const data = await fetchJson<ProcessStatusResponse>(`/${action}`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ process: currentProcess }),
      });
      notify(String(data.output || data.pm2_output || data.message || "OK"));
      await refreshProcess();
    } catch (reason) {
      notify((reason as Error).message);
    } finally {
      setBusy(null);
    }
  };

  const serviceAction = async (serviceId: string, action: "start" | "restart" | "stop") => {
    setBusy(`${serviceId}:${action}`);
    try {
      const data = await fetchJson<ServiceItem>("/service_action", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ service: serviceId, action }),
      });
      notify(data.message || "OK");
      await refreshServices();
    } catch (reason) {
      notify((reason as Error).message);
    } finally {
      setBusy(null);
    }
  };

  const saveFile = async () => {
    if (!rootId || !filePath) return;
    setBusy("file:save");
    try {
      await fetchJson("/managed_file", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ root: rootId, path: filePath, content: fileContent }),
      });
      notify(tr("文件已保存", "File saved"));
      await refreshFiles(rootId, filePath);
    } catch (reason) {
      notify((reason as Error).message);
    } finally {
      setBusy(null);
    }
  };

  const createFile = async () => {
    if (!currentRoot?.allow_create) {
      notify(tr("当前目录不允许新建文件", "The current root does not allow new files"));
      return;
    }
    const nextPath = window.prompt(tr("请输入新的相对路径", "Enter a new relative path"), currentRoot.default_file || "");
    if (!nextPath) return;
    setBusy("file:create");
    try {
      await fetchJson("/managed_file", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ root: rootId, path: nextPath, content: "" }),
      });
      notify(tr("文件已创建", "File created"));
      await refreshFiles(rootId, nextPath);
    } catch (reason) {
      notify((reason as Error).message);
    } finally {
      setBusy(null);
    }
  };

  const deleteFile = async () => {
    if (!rootId || !filePath) return;
    if (!currentRoot?.allow_delete) {
      notify(tr("当前目录不允许删除文件", "The current root does not allow deletion"));
      return;
    }
    if (!window.confirm(tr("确定删除该文件？", "Delete this file?"))) return;
    setBusy("file:delete");
    try {
      await fetchJson(
        `/managed_file?root=${encodeURIComponent(rootId)}&path=${encodeURIComponent(filePath)}`,
        { method: "DELETE" },
      );
      notify(tr("文件已删除", "File deleted"));
      await refreshFiles(rootId);
    } catch (reason) {
      notify((reason as Error).message);
    } finally {
      setBusy(null);
    }
  };

  const importManagedFile = async (event: ChangeEvent<HTMLInputElement>) => {
    const upload = event.target.files?.[0];
    event.target.value = "";
    setFileImportKey((value) => value + 1);
    if (!upload || !rootId) return;

    setBusy("file:import");
    try {
      const content = await upload.text();
      await fetchJson("/managed_file", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ root: rootId, path: upload.name, content }),
      });
      notify(tr("导入完成，已替换同名文件", "Import finished and replaced matching file"));
      setFilePath(upload.name);
      await refreshFiles(rootId, upload.name);
    } catch (reason) {
      notify((reason as Error).message);
    } finally {
      setBusy(null);
    }
  };

  const sendAndroidAction = async (action: string, payload?: Record<string, unknown>) => {
    if (!androidSerial) {
      notify(tr("当前没有可用的 ADB 设备", "No active ADB device"));
      return;
    }
    setBusy(`android:${action}`);
    try {
      const data = await fetchJson<{ message?: string; output?: string }>("/android/action", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ action, serial: androidSerial, payload: payload || {} }),
      });
      notify(data.message || "OK");
      if (data.output) setAndroidOutput(data.output);
      setShotNonce(Date.now());
      await refreshAndroidOverview(androidSerial);
    } catch (reason) {
      notify((reason as Error).message);
    } finally {
      setBusy(null);
    }
  };

  const previewActionLabel =
    previewMode === "tap"
      ? tr("点击", "Tap")
      : previewMode === "double_tap"
        ? tr("双击", "Double Tap")
        : tr("长按", "Long Press");

  const handlePreviewClick = async (event: MouseEvent<HTMLImageElement>) => {
    if (!androidSerial) {
      notify(tr("当前没有可用的 ADB 设备", "No active ADB device"));
      return;
    }
    const rect = event.currentTarget.getBoundingClientRect();
    const sourceWidth = androidResolution?.width || event.currentTarget.naturalWidth || rect.width;
    const sourceHeight = androidResolution?.height || event.currentTarget.naturalHeight || rect.height;
    const x = Math.max(
      0,
      Math.min(sourceWidth, Math.round((event.clientX - rect.left) * (sourceWidth / rect.width))),
    );
    const y = Math.max(
      0,
      Math.min(sourceHeight, Math.round((event.clientY - rect.top) * (sourceHeight / rect.height))),
    );
    setPreviewPoint({ x, y });
    if (previewMode === "long_press") {
      await sendAndroidAction("long_press", { x, y, duration: 750 });
      return;
    }
    await sendAndroidAction(previewMode, { x, y });
  };

  const serviceHref = (item: ServiceItem) => {
    if (item.service_id === "shellcrash" && stack?.control_url) {
      return `${stack.control_url}/shellcrash?lang=${lang}`;
    }
    if (item.service_id === "android_panel" && stack?.control_url) {
      return `${stack.control_url}/android?lang=${lang}`;
    }
    return item.url || "";
  };

  const statusText = (status: string) =>
    ({
      online: tr("在线", "Online"),
      stopped: tr("已停止", "Stopped"),
      configured: tr("已配置", "Configured"),
      unavailable: tr("未安装", "Unavailable"),
    }[status] || status);

  const activeRoots = tab === "shellcrash" ? shellRoots : otherRoots;

  const tabEmoji: Record<TabKey, string> = {
    overview: "📊",
    business: "🎬",
    modules: "🧩",
    shellcrash: "🛡️",
    android: "🤖",
    config: "⚙️",
  };

  return (
    <>
    <main className="safe-pb-nav mx-auto min-h-screen max-w-7xl px-4 pb-16 pt-8 sm:px-6 lg:px-10">
      {toast ? (
        <div className="animate-toast-in fixed bottom-6 left-1/2 z-50 -translate-x-1/2 rounded-2xl border border-cyan-500/25 bg-slate-950/95 px-5 py-3 text-sm text-cyan-50">
          {toast}
        </div>
      ) : null}

      <header className="mb-8 flex flex-col gap-4">
        <div className="flex flex-col gap-4 lg:flex-row lg:items-end lg:justify-between">
          <div>
            <p className="text-[11px] font-semibold uppercase tracking-[0.22em] text-cyan-400/90">
              {tr("超级业务中心 / 模块控制台", "Super Hub / Control Plane")}
            </p>
            <h1 className="mt-2 text-3xl font-bold text-[color:var(--text)] sm:text-4xl">
              {tr("无人直播 · Linux 超级业务中心", "Unmanned Live · Linux Super Hub")}
            </h1>
            <p className="mt-3 max-w-3xl text-sm text-slate-400">
              {tr(
                "抖音 → YouTube / HDMI 转播、ws-scrcpy、Chromium 与可选 Neko 浏览器、ShellCrash 等模块解耦，单点故障不拖垮整机。",
                "Douyin→YouTube/HDMI relay, ws-scrcpy, Chromium & optional Neko, ShellCrash — decoupled modules.",
              )}
            </p>
          </div>
          <div className="flex flex-wrap items-center gap-3">
            <div className="rounded-2xl border border-white/8 bg-black/20 px-4 py-3 text-xs text-slate-300">
              {(stack?.mdns_host || "live.local") +
                " | " +
                (stack?.machine || "unknown") +
                " | " +
                (stack?.kernel || "unknown")}
            </div>
            <Button
              className={lang === "zh" ? "border border-cyan-400/50 bg-cyan-500/10" : "border border-white/12 bg-black/20"}
              onClick={() => setLang("zh")}
            >
              中文
            </Button>
            <Button
              className={lang === "en" ? "border border-cyan-400/50 bg-cyan-500/10" : "border border-white/12 bg-black/20"}
              onClick={() => setLang("en")}
            >
              EN
            </Button>
            <Button
              className={theme === "light" ? "border border-amber-400/50 bg-amber-500/15" : "border border-white/12 bg-black/20"}
              onClick={() => setTheme("light")}
              title={tr("日间主题", "Light theme")}
            >
              {tr("☀️ 日间", "☀️ Light")}
            </Button>
            <Button
              className={theme === "dark" ? "border border-indigo-400/50 bg-indigo-500/15" : "border border-white/12 bg-black/20"}
              onClick={() => setTheme("dark")}
              title={tr("夜间主题", "Dark theme")}
            >
              {tr("🌙 夜间", "🌙 Dark")}
            </Button>
            <Button className="border border-white/12 bg-black/20" onClick={() => void boot()}>
              {tr("刷新", "Refresh")}
            </Button>
          </div>
        </div>

        <nav className="flex flex-wrap gap-2">
          {TABS.map((item) => (
            <button
              key={item}
              className={`btn-focus rounded-2xl px-4 py-2 text-sm ${
                tab === item
                  ? "border border-cyan-400/50 bg-cyan-500/10 text-cyan-100"
                  : "border border-white/10 bg-black/20 text-slate-300"
              }`}
              onClick={() => setTab(item)}
            >
              {{
                overview: tr("总览", "Overview"),
                business: tr("业务", "Business"),
                modules: tr("系统模块", "Modules"),
                shellcrash: "ShellCrash",
                android: tr("安卓设备", "Android"),
                config: tr("配置中心", "Config"),
              }[item]}
            </button>
          ))}
        </nav>
      </header>

      {booting ? (
        <div className="glass rounded-3xl py-24 text-center text-slate-400">
          {tr("正在连接控制台...", "Connecting to the control plane...")}
        </div>
      ) : null}

      {!booting && error ? (
        <div className="glass rounded-3xl border border-rose-500/25 bg-rose-950/20 p-8 text-center text-rose-200">
          {error}
        </div>
      ) : null}

      {!booting && !error ? (
        <div className="grid gap-6">
          {tab === "overview" ? (
            <>
              <section className="grid gap-6 xl:grid-cols-12">
                <article className="glass rounded-3xl p-6 xl:col-span-4">
                  <h2 className="text-lg font-semibold text-[color:var(--text)]">
                    {tr("🛰️ 流媒体与桌面入口", "Streaming & desktop")}
                  </h2>
                  <p className="mt-1 text-xs text-slate-400 [html[data-theme=light]_&]:text-slate-600">
                    {tr(
                      "ws-scrcpy：浏览器里控安卓；Chromium：本机+油猴+RemoteDebug；Neko：可选 Docker 远程桌面开 YouTube。",
                      "ws-scrcpy: browser ADB; Chromium: host+Tampermonkey+9222; Neko: optional Docker desktop.",
                    )}
                  </p>
                  <div className="mt-4 flex max-h-[28rem] flex-col gap-2 overflow-y-auto pr-1 log-scroll">
                    {stack?.dashboard_url ? (
                      <a
                        className="btn-focus rounded-2xl border border-white/10 bg-black/20 px-4 py-2.5 text-sm text-slate-100 transition hover:border-cyan-400/30 [html[data-theme=light]_&]:border-slate-200 [html[data-theme=light]_&]:bg-white/60 [html[data-theme=light]_&]:text-slate-800"
                        href={stack.dashboard_url}
                        target="_blank"
                        rel="noreferrer"
                      >
                        🏠 Homepage
                      </a>
                    ) : null}
                    {stack?.control_url ? (
                      <>
                        <a
                          className="btn-focus rounded-2xl border border-white/10 bg-black/20 px-4 py-2.5 text-sm text-slate-100 transition hover:border-cyan-400/30 [html[data-theme=light]_&]:border-slate-200 [html[data-theme=light]_&]:bg-white/60 [html[data-theme=light]_&]:text-slate-800"
                          href={`${stack.control_url}?tab=shellcrash&lang=${lang}`}
                          target="_blank"
                          rel="noreferrer"
                        >
                          🛡️ ShellCrash
                        </a>
                        <a
                          className="btn-focus rounded-2xl border border-white/10 bg-black/20 px-4 py-2.5 text-sm text-slate-100 transition hover:border-cyan-400/30 [html[data-theme=light]_&]:border-slate-200 [html[data-theme=light]_&]:bg-white/60 [html[data-theme=light]_&]:text-slate-800"
                          href={`${stack.control_url}?tab=android&lang=${lang}`}
                          target="_blank"
                          rel="noreferrer"
                        >
                          🤖 {tr("安卓中心 (含 ws-scrcpy)", "Android hub + ws-scrcpy")}
                        </a>
                        <a
                          className="btn-focus rounded-2xl border border-white/10 bg-black/20 px-4 py-2.5 text-sm text-slate-100 transition hover:border-cyan-400/30 [html[data-theme=light]_&]:border-slate-200 [html[data-theme=light]_&]:bg-white/60 [html[data-theme=light]_&]:text-slate-800"
                          href={`${stack.control_url}?tab=config&lang=${lang}`}
                          target="_blank"
                          rel="noreferrer"
                        >
                          ⚙️ {tr("配置中心", "Config")}
                        </a>
                      </>
                    ) : null}
                    {ql.ws_scrcpy ? (
                      <a
                        className="btn-focus rounded-2xl border border-cyan-500/25 bg-cyan-500/10 px-4 py-2.5 text-sm text-cyan-50 transition hover:border-cyan-400/50 [html[data-theme=light]_&]:border-cyan-300 [html[data-theme=light]_&]:bg-cyan-50 [html[data-theme=light]_&]:text-cyan-950"
                        href={ql.ws_scrcpy}
                        target="_blank"
                        rel="noreferrer"
                      >
                        📱 ws-scrcpy ({tr("原始流控制页", "raw stream UI")})
                      </a>
                    ) : null}
                    {ql.chromium_remote_debug ? (
                      <a
                        className="btn-focus rounded-2xl border border-white/10 bg-black/20 px-4 py-2.5 text-sm text-slate-100 transition hover:border-violet-400/30 [html[data-theme=light]_&]:border-slate-200 [html[data-theme=light]_&]:bg-white/60 [html[data-theme=light]_&]:text-slate-800"
                        href={ql.chromium_remote_debug}
                        target="_blank"
                        rel="noreferrer"
                      >
                        🧪 {tr("Chromium RemoteDebug (9222)", "Chromium RemoteDebug")}
                      </a>
                    ) : null}
                    {ql.neko_browser ? (
                      <a
                        className="btn-focus rounded-2xl border border-amber-500/20 bg-amber-500/10 px-4 py-2.5 text-sm text-amber-50 transition hover:border-amber-400/40 [html[data-theme=light]_&]:border-amber-200 [html[data-theme=light]_&]:bg-amber-50 [html[data-theme=light]_&]:text-amber-950"
                        href={ql.neko_browser}
                        target="_blank"
                        rel="noreferrer"
                      >
                        🐱 Neko / {tr("Docker 浏览器桌面", "Docker browser desktop")}
                      </a>
                    ) : null}
                    {ql.webtty ? (
                      <a
                        className="btn-focus rounded-2xl border border-white/10 bg-black/20 px-4 py-2.5 text-sm text-slate-100 [html[data-theme=light]_&]:border-slate-200 [html[data-theme=light]_&]:bg-white/60 [html[data-theme=light]_&]:text-slate-800"
                        href={ql.webtty}
                        target="_blank"
                        rel="noreferrer"
                      >
                        ⌨️ WebTTY
                      </a>
                    ) : null}
                    {ql.filebrowser ? (
                      <a
                        className="btn-focus rounded-2xl border border-white/10 bg-black/20 px-4 py-2.5 text-sm text-slate-100 [html[data-theme=light]_&]:border-slate-200 [html[data-theme=light]_&]:bg-white/60 [html[data-theme=light]_&]:text-slate-800"
                        href={ql.filebrowser}
                        target="_blank"
                        rel="noreferrer"
                      >
                        📂 File Browser
                      </a>
                    ) : null}
                    {ql.netdata ? (
                      <a
                        className="btn-focus rounded-2xl border border-white/10 bg-black/20 px-4 py-2.5 text-sm text-slate-100 [html[data-theme=light]_&]:border-slate-200 [html[data-theme=light]_&]:bg-white/60 [html[data-theme=light]_&]:text-slate-800"
                        href={ql.netdata}
                        target="_blank"
                        rel="noreferrer"
                      >
                        📈 Netdata
                      </a>
                    ) : null}
                    {ql.srs_http ? (
                      <a
                        className="btn-focus rounded-2xl border border-white/10 bg-black/20 px-4 py-2.5 text-sm text-slate-100 [html[data-theme=light]_&]:border-slate-200 [html[data-theme=light]_&]:bg-white/60 [html[data-theme=light]_&]:text-slate-800"
                        href={ql.srs_http}
                        target="_blank"
                        rel="noreferrer"
                      >
                        🎞️ SRS HTTP
                      </a>
                    ) : null}
                  </div>
                </article>

                <article className="glass rounded-3xl p-6 xl:col-span-4">
                  <h2 className="text-lg font-semibold text-white">{tr("节点状态", "Node Status")}</h2>
                  <div className="mt-4 rounded-2xl border border-white/8 bg-black/20 p-4 text-sm text-slate-300">
                    <p>{stack?.mdns_host || "live.local"}</p>
                    <p className="mt-2">IP: {(stack?.ips || []).join(" / ") || "-"}</p>
                    <p className="mt-2">{stack?.machine || "-"}</p>
                    <p className="mt-2">{stack?.kernel || "-"}</p>
                  </div>
                </article>

                <article className="glass rounded-3xl p-6 xl:col-span-4">
                  <h2 className="text-lg font-semibold text-[color:var(--text)]">{tr("系统快照", "System Snapshot")}</h2>
                  <div className="mt-4 rounded-2xl border border-white/8 bg-black/20 p-4 text-sm text-slate-300 [html[data-theme=light]_&]:border-slate-200/80 [html[data-theme=light]_&]:bg-white/50 [html[data-theme=light]_&]:text-slate-700">
                    <p>
                      CPU:{" "}
                      {[snapshot?.cpu_load?.["1m"], snapshot?.cpu_load?.["5m"], snapshot?.cpu_load?.["15m"]]
                        .map((item) => (typeof item === "number" ? item.toFixed(2) : "0.00"))
                        .join(" / ")}
                    </p>
                    <p className="mt-2">RAM: {formatBytes(snapshot?.memory?.available)} / {formatBytes(snapshot?.memory?.total)}</p>
                    <p className="mt-2">Disk: {formatBytes(snapshot?.disk?.free)} / {formatBytes(snapshot?.disk?.total)}</p>
                    <p className="mt-2">Netdata: {snapshot?.netdata?.available ? snapshot.netdata.version || "online" : "offline"}</p>
                  </div>
                  <OverviewCharts snapshot={snapshot} theme={theme} tr={tr} />
                </article>
              </section>

              <section className="glass rounded-3xl p-6">
                <h2 className="text-lg font-semibold text-white">{tr("模块概况", "Module Summary")}</h2>
                <div className="mt-4 grid gap-4 md:grid-cols-2 xl:grid-cols-3">
                  {services.map((item) => (
                    <div key={item.service_id} className="rounded-3xl border border-white/8 bg-black/20 p-5">
                      <div className="flex items-start justify-between gap-3">
                        <div>
                          <h3 className="text-base font-semibold text-white">{item.label}</h3>
                          <p className="mt-1 text-xs text-slate-400">{item.description}</p>
                        </div>
                        <span className={`rounded-full border px-2.5 py-1 text-xs ${statusTone(item.status)}`}>{statusText(item.status)}</span>
                      </div>
                      <p className="mt-3 min-h-[3rem] text-xs text-slate-500">{item.detail || "-"}</p>
                      {serviceHref(item) ? (
                        <a className="btn-focus mt-3 inline-flex rounded-xl border border-white/12 px-3 py-2 text-xs text-slate-200" href={serviceHref(item)} target="_blank" rel="noreferrer">{tr("打开", "Open")}</a>
                      ) : null}
                    </div>
                  ))}
                </div>
              </section>
            </>
          ) : null}

          {tab === "business" ? (
            <section className="grid gap-6 xl:grid-cols-12">
              <article className="glass rounded-3xl p-6 xl:col-span-4">
                <h2 className="text-lg font-semibold text-white">{tr("业务运行时", "Business Runtime")}</h2>
                <p className="mt-2 text-xs text-slate-400">{tr("这里只放业务脚本本身，Hub 基座可单独运行。", "Only business processes live here.")}</p>
                {entries.length > 0 ? (
                  <>
                    <select className="mt-4 w-full rounded-2xl border border-white/12 bg-slate-950/60 px-4 py-3 text-sm text-white" value={currentProcess} onChange={(event) => setCurrentProcess(event.target.value)}>
                      {entries.map((item) => (
                        <option key={item.pm2} value={item.pm2}>{item.label} | {item.script}</option>
                      ))}
                    </select>
                    <div className="mt-4 flex items-center justify-between rounded-2xl border border-white/8 bg-black/20 px-4 py-3">
                      <span className={`rounded-full border px-3 py-1 text-xs ${statusTone(processStatus)}`}>{statusText(processStatus)}</span>
                      <Button className="border border-white/12 bg-black/20" onClick={() => void refreshProcess()}>{tr("轮询", "Poll")}</Button>
                    </div>
                    <div className="mt-4 grid grid-cols-2 gap-2">
                      <Button className="bg-emerald-600" disabled={busy === "process:start"} onClick={() => void processAction("start")}>{busy === "process:start" ? tr("启动中...", "Starting...") : tr("启动", "Start")}</Button>
                      <Button className="bg-amber-600" disabled={busy === "process:restart"} onClick={() => void processAction("restart")}>{busy === "process:restart" ? tr("重启中...", "Restarting...") : tr("重启", "Restart")}</Button>
                      <Button className="col-span-2 bg-rose-600" disabled={busy === "process:stop"} onClick={() => void processAction("stop")}>{busy === "process:stop" ? tr("停止中...", "Stopping...") : tr("停止", "Stop")}</Button>
                    </div>
                  </>
                ) : (
                  <div className="mt-4 rounded-2xl border border-dashed border-white/12 bg-black/20 p-4 text-sm text-slate-400">
                    {tr("未发现业务进程。若只部署了 Hub 基座，这是正常状态。", "No business process discovered.")}
                  </div>
                )}
              </article>
              <article className="glass rounded-3xl p-6 xl:col-span-8">
                <h2 className="text-lg font-semibold text-white">{tr("业务日志", "Process Logs")}</h2>
                <div className="mt-4 grid gap-4 lg:grid-cols-2">
                  <pre className="log-scroll min-h-[22rem] rounded-2xl border border-emerald-500/15 bg-black/55 p-4 font-mono text-[11px] text-emerald-100/95">{recentLog || tr("暂无输出", "No stdout yet.")}</pre>
                  <pre className="log-scroll min-h-[22rem] rounded-2xl border border-rose-500/15 bg-black/55 p-4 font-mono text-[11px] text-rose-100/95">{recentError || tr("暂无报错", "No stderr yet.")}</pre>
                </div>
              </article>
            </section>
          ) : null}

          {tab === "modules" ? (
            <section className="grid gap-6 xl:grid-cols-12">
              <article className="glass rounded-3xl p-6 xl:col-span-8">
                <div className="flex items-center justify-between gap-3">
                  <div>
                    <h2 className="text-lg font-semibold text-white">{tr("系统模块", "System Modules")}</h2>
                    <p className="mt-2 text-xs text-slate-400">{tr("每个模块都独立启停和降级，避免一个服务异常拖垮整套业务。", "Each module starts and degrades independently.")}</p>
                  </div>
                  <Button className="border border-white/12 bg-black/20" onClick={() => void refreshServices()}>{tr("刷新服务", "Refresh Services")}</Button>
                </div>
                <div className="mt-4 grid gap-4 md:grid-cols-2">
                  {services.map((item) => (
                    <div key={item.service_id} className="rounded-3xl border border-white/8 bg-black/20 p-5">
                      <div className="flex items-start justify-between gap-3">
                        <div>
                          <h3 className="text-base font-semibold text-white">{item.label}</h3>
                          <p className="mt-1 text-xs text-slate-400">{item.description}</p>
                        </div>
                        <span className={`rounded-full border px-2.5 py-1 text-xs ${statusTone(item.status)}`}>{statusText(item.status)}</span>
                      </div>
                      <p className="mt-3 min-h-[3rem] text-xs text-slate-500">{item.detail || "-"}</p>
                      <div className="mt-4 flex flex-wrap gap-2">
                        <Button className="bg-emerald-600" disabled={!item.available || !!busy} onClick={() => void serviceAction(item.service_id, "start")}>{tr("启动", "Start")}</Button>
                        <Button className="bg-amber-600" disabled={!item.available || !!busy} onClick={() => void serviceAction(item.service_id, "restart")}>{tr("重启", "Restart")}</Button>
                        <Button className="bg-rose-600" disabled={!item.available || !!busy} onClick={() => void serviceAction(item.service_id, "stop")}>{tr("停止", "Stop")}</Button>
                        {serviceHref(item) ? <a className="btn-focus rounded-xl border border-white/12 px-3 py-2 text-xs text-slate-200" href={serviceHref(item)} target="_blank" rel="noreferrer">{tr("打开", "Open")}</a> : null}
                      </div>
                    </div>
                  ))}
                </div>
              </article>
              <article className="glass rounded-3xl p-6 xl:col-span-4">
                <h2 className="text-lg font-semibold text-white">{tr("硬件与系统", "Hardware and System")}</h2>
                <div className="mt-4 rounded-2xl border border-white/8 bg-black/20 p-4 text-xs text-slate-400">
                  <p>Arch: {hardware?.arch || "-"}</p>
                  <p className="mt-2">FFmpeg: {(hardware?.ffmpeg_hwaccels || []).join(", ") || "-"}</p>
                  <p className="mt-2">GPU: {hardware?.gpu?.present ? hardware.gpu.driver || "present" : "none"}</p>
                  <p className="mt-2">NPU: {hardware?.npu?.present ? (hardware.npu.devices || []).join(", ") : "none"}</p>
                  <p className="mt-2">Decoder: {hardware?.recommendation?.video_decoder || "cpu"}</p>
                  <p className="mt-2">HDMI: {hardware?.recommendation?.hdmi_player || "cpu"}</p>
                  <p className="mt-2">Mode: {hardware?.recommendation?.stability_mode || "safe"}</p>
                </div>
              </article>
            </section>
          ) : null}

          {tab === "shellcrash" ? (
            <section className="grid gap-6 xl:grid-cols-12">
              <article className="glass rounded-3xl p-6 xl:col-span-4">
                <h2 className="text-lg font-semibold text-white">ShellCrash</h2>
                <p className="mt-2 text-xs text-slate-400">{tr("这里不再依赖命令行菜单，直接做 YAML / JSON / CFG 编辑与服务控制。", "Manage ShellCrash from the web instead of the shell menu.")}</p>
                {shellcrashService ? (
                  <div className="mt-4 rounded-3xl border border-white/8 bg-black/20 p-5">
                    <div className="flex items-start justify-between gap-3">
                      <div>
                        <h3 className="text-base font-semibold text-white">{shellcrashService.label}</h3>
                        <p className="mt-1 text-xs text-slate-400">{shellcrashService.description}</p>
                      </div>
                      <span className={`rounded-full border px-2.5 py-1 text-xs ${statusTone(shellcrashService.status)}`}>{statusText(shellcrashService.status)}</span>
                    </div>
                    <p className="mt-3 text-xs text-slate-500">{shellcrashService.detail || "-"}</p>
                    <div className="mt-4 flex flex-wrap gap-2">
                      <Button className="bg-emerald-600" disabled={!shellcrashService.available || !!busy} onClick={() => void serviceAction("shellcrash", "start")}>{tr("启动", "Start")}</Button>
                      <Button className="bg-amber-600" disabled={!shellcrashService.available || !!busy} onClick={() => void serviceAction("shellcrash", "restart")}>{tr("重启", "Restart")}</Button>
                      <Button className="bg-rose-600" disabled={!shellcrashService.available || !!busy} onClick={() => void serviceAction("shellcrash", "stop")}>{tr("停止", "Stop")}</Button>
                    </div>
                  </div>
                ) : null}
                <div className="mt-4 rounded-2xl border border-white/8 bg-black/20 p-4 text-xs text-slate-400">
                  <p className="text-white">{tr("快捷文件", "Quick Files")}</p>
                  <div className="mt-3 grid gap-2">
                    <button className="btn-focus rounded-xl border border-white/10 px-3 py-2 text-left text-slate-200" onClick={() => void openManagedFile("shellcrash-yamls", "config.yaml")}>config.yaml</button>
                    <button className="btn-focus rounded-xl border border-white/10 px-3 py-2 text-left text-slate-200" onClick={() => void openManagedFile("shellcrash-configs", "ShellCrash.cfg")}>ShellCrash.cfg</button>
                    <button className="btn-focus rounded-xl border border-white/10 px-3 py-2 text-left text-slate-200" onClick={() => void openManagedFile("shellcrash-configs", "servers.list")}>servers.list</button>
                    <button className="btn-focus rounded-xl border border-white/10 px-3 py-2 text-left text-slate-200" onClick={() => void openManagedFile("shellcrash-configs", "command.env")}>command.env</button>
                  </div>
                </div>
              </article>
              <article className="glass rounded-3xl p-6 xl:col-span-8">
                <div className="flex items-center justify-between gap-3">
                  <div>
                    <h2 className="text-lg font-semibold text-white">{tr("ShellCrash 文件编辑器", "ShellCrash Editor")}</h2>
                    <p className="mt-2 text-xs text-slate-400">{tr("支持查看、修改、新建、删除，路径被限制在 ShellCrash 托管目录内。", "View, edit, create and delete files inside managed ShellCrash roots.")}</p>
                  </div>
                  <div className="flex flex-wrap gap-2">
                    <label className={`btn-focus rounded-xl border border-white/12 px-3 py-2 text-xs text-slate-100 ${busy ? "cursor-not-allowed opacity-40" : ""}`}>
                      {busy === "file:import" ? tr("导入中...", "Importing...") : tr("导入/替换", "Import/Replace")}
                      <input key={fileImportKey} className="hidden" disabled={!!busy} type="file" accept=".yaml,.yml,.json,.cfg,.env,.list,.txt" onChange={(event) => void importManagedFile(event)} />
                    </label>
                    <Button className="bg-cyan-600" disabled={!filePath || !!busy} onClick={() => void saveFile()}>{busy === "file:save" ? tr("保存中...", "Saving...") : tr("保存", "Save")}</Button>
                  </div>
                </div>
                <div className="mt-4 grid gap-6 xl:grid-cols-[18rem,1fr]">
                  <div>
                    <select className="w-full rounded-2xl border border-white/12 bg-slate-950/60 px-4 py-3 text-sm text-white" value={rootId} onChange={(event) => { setRootId(event.target.value); setFilePath(""); }}>
                      {shellRoots.map((item) => (
                        <option key={item.root_id} value={item.root_id}>{item.label} | {item.file_count}</option>
                      ))}
                    </select>
                    <div className="mt-4 flex flex-wrap gap-2">
                      <Button className="bg-cyan-600" disabled={!!busy} onClick={() => void createFile()}>{tr("新建", "New")}</Button>
                      <Button className="bg-rose-600" disabled={!filePath || !!busy} onClick={() => void deleteFile()}>{tr("删除", "Delete")}</Button>
                    </div>
                    <div className="mt-4 space-y-2">
                      {files.map((item) => (
                        <button key={item.path} className={`btn-focus w-full rounded-2xl border px-4 py-3 text-left ${filePath === item.path ? "border-cyan-500/40 bg-cyan-500/10" : "border-white/8 bg-black/20"}`} onClick={() => setFilePath(item.path)}>
                          <div className="truncate text-sm text-white">{item.path}</div>
                          <div className="mt-1 text-[11px] text-slate-500">{formatBytes(item.size)}</div>
                        </button>
                      ))}
                    </div>
                  </div>
                  <div>
                    <div className="rounded-2xl border border-white/8 bg-black/20 px-4 py-3 font-mono text-[11px] text-slate-500">{filePath ? `${rootId} / ${filePath}` : tr("请选择文件", "Pick a file")}</div>
                    <textarea className="log-scroll mt-4 min-h-[32rem] w-full resize-y rounded-2xl border border-white/10 bg-black/45 p-4 font-mono text-xs leading-relaxed text-slate-200" spellCheck={false} value={fileContent} onChange={(event) => setFileContent(event.target.value)} />
                  </div>
                </div>
              </article>
            </section>
          ) : null}

          {tab === "android" ? (
            <section className="grid gap-6 xl:grid-cols-12">
              <article className="glass rounded-3xl p-6 xl:col-span-4">
                <div className="flex items-center justify-between gap-3">
                  <div>
                    <h2 className="text-lg font-semibold text-white">{tr("安卓设备中心", "Android Device Center")}</h2>
                    <p className="mt-2 text-xs text-slate-400">{tr("把设备发现、截图预览、ADB 动作和原始 web-scrcpy 放到一个模块里。", "Combine discovery, preview, ADB actions and raw web-scrcpy in one module.")}</p>
                  </div>
                  <Button className="border border-white/12 bg-black/20" onClick={() => void (async () => { const serial = await refreshAndroidDevices(); if (serial) await Promise.all([refreshAndroidOverview(serial), refreshAndroidUi(serial), refreshAndroidPackages(serial)]); setShotNonce(Date.now()); })()}>{tr("刷新设备", "Refresh")}</Button>
                </div>
                <div className="mt-4 rounded-2xl border border-white/8 bg-black/20 p-4">
                  <p className="text-sm font-semibold text-white">{tr("已连接设备", "Devices")}</p>
                  {!androidAvailable || androidDevices.length === 0 ? (
                    <p className="mt-3 text-sm text-slate-400">{tr("当前没有可用的 ADB 设备。", "No active ADB device.")}</p>
                  ) : (
                    <div className="mt-3 space-y-2">
                      {androidDevices.map((item) => (
                        <button key={item.serial} className={`btn-focus w-full rounded-2xl border px-4 py-3 text-left ${androidSerial === item.serial ? "border-cyan-500/40 bg-cyan-500/10" : "border-white/8 bg-black/20"}`} onClick={() => { setAndroidSerial(item.serial); void Promise.all([refreshAndroidOverview(item.serial), refreshAndroidUi(item.serial), refreshAndroidPackages(item.serial)]); setShotNonce(Date.now()); }}>
                          <div className="text-sm text-white">{item.model || item.device || item.serial}</div>
                          <div className="mt-1 text-[11px] text-slate-500">{item.serial} | {item.state}</div>
                        </button>
                      ))}
                    </div>
                  )}
                </div>
                <div className="mt-4 rounded-2xl border border-white/8 bg-black/20 p-4 text-xs text-slate-400">
                  <p className="text-white">{tr("设备状态", "Device Status")}</p>
                  <p className="mt-2">{androidOverview?.brand || "-"} {androidOverview?.model || "-"}</p>
                  <p className="mt-2">Android {androidOverview?.android_version || "-"} / SDK {androidOverview?.sdk || "-"}</p>
                  <p className="mt-2 whitespace-pre-wrap">{androidOverview?.battery || "-"}</p>
                  <p className="mt-2 whitespace-pre-wrap">{androidOverview?.resolution || "-"}</p>
                  <p className="mt-2 whitespace-pre-wrap">{androidOverview?.focus || "-"}</p>
                </div>
              </article>
              <article className="glass rounded-3xl p-6 xl:col-span-8">
                <div className="flex items-center justify-between gap-3">
                  <div>
                    <h2 className="text-lg font-semibold text-white">{tr("屏幕预览与动作", "Screen Preview and Actions")}</h2>
                    <p className="mt-2 text-xs text-slate-400">{tr("预览图支持直接点按/双击/长按，配合 UI 节点和包管理形成更完整的安卓控制台。", "The preview supports tap, double tap and long press, backed by UI nodes and package tools.")}</p>
                  </div>
                  <div className="flex flex-wrap gap-2">
                    <Button className={`border border-white/12 ${previewMode === "tap" ? "bg-cyan-600" : "bg-black/20"}`} disabled={!androidSerial || !!busy} onClick={() => setPreviewMode("tap")}>{tr("点击", "Tap")}</Button>
                    <Button className={`border border-white/12 ${previewMode === "double_tap" ? "bg-cyan-600" : "bg-black/20"}`} disabled={!androidSerial || !!busy} onClick={() => setPreviewMode("double_tap")}>{tr("双击", "Double Tap")}</Button>
                    <Button className={`border border-white/12 ${previewMode === "long_press" ? "bg-cyan-600" : "bg-black/20"}`} disabled={!androidSerial || !!busy} onClick={() => setPreviewMode("long_press")}>{tr("长按", "Long Press")}</Button>
                    <Button className="border border-white/12 bg-black/20" disabled={!androidSerial} onClick={() => setShotNonce(Date.now())}>{tr("刷新截图", "Refresh Shot")}</Button>
                  </div>
                </div>
                <div className="mt-4 overflow-hidden rounded-3xl border border-white/8 bg-black/35 p-4">
                  {androidSerial ? (
                    <>
                      <div className="mb-3 flex flex-wrap items-center gap-3 text-xs text-slate-400">
                        <span>{tr("当前动作", "Current action")}: {previewActionLabel}</span>
                        <span>{tr("分辨率", "Resolution")}: {androidOverview?.resolution || "-"}</span>
                        <span>{tr("最近坐标", "Last point")}: {previewPoint ? `${previewPoint.x}, ${previewPoint.y}` : "-"}</span>
                      </div>
                      <img alt="Android preview" className="max-h-[30rem] w-full cursor-crosshair rounded-2xl object-contain bg-black" onClick={(event) => void handlePreviewClick(event)} src={`${base}/android/screenshot?serial=${encodeURIComponent(androidSerial)}&ts=${shotNonce}`} />
                    </>
                  ) : <div className="flex min-h-[18rem] items-center justify-center rounded-2xl border border-dashed border-white/10 bg-black/20 text-sm text-slate-500">{tr("当前没有可用的 ADB 设备。", "No active ADB device.")}</div>}
                </div>
                <div className="mt-6 grid gap-6 xl:grid-cols-3">
                  <div className="rounded-3xl border border-white/8 bg-black/20 p-5">
                    <h3 className="text-base font-semibold text-white">{tr("快捷控制", "Quick Controls")}</h3>
                    <div className="mt-4 grid grid-cols-3 gap-2">
                      {[
                        ["HOME", "KEYCODE_HOME"], ["BACK", "KEYCODE_BACK"], ["RECENTS", "KEYCODE_APP_SWITCH"],
                        ["POWER", "KEYCODE_POWER"], ["NOTIFY", "KEYCODE_NOTIFICATION"], ["VOL+", "KEYCODE_VOLUME_UP"],
                        ["VOL-", "KEYCODE_VOLUME_DOWN"],
                      ].map(([label, keycode]) => (
                        <button key={label} className="btn-focus rounded-xl border border-white/10 bg-slate-950/50 px-3 py-3 text-xs text-slate-100" disabled={!androidSerial || !!busy} onClick={() => void sendAndroidAction("key", { keycode })}>{label}</button>
                      ))}
                      <button className="btn-focus rounded-xl border border-white/10 bg-slate-950/50 px-3 py-3 text-xs text-slate-100" disabled={!androidSerial || !!busy} onClick={() => void sendAndroidAction("wake")}>WAKE</button>
                      <button className="btn-focus rounded-xl border border-white/10 bg-slate-950/50 px-3 py-3 text-xs text-slate-100" disabled={!androidSerial || !!busy} onClick={() => void sendAndroidAction("rotate", { rotation: "0" })}>Portrait</button>
                      <button className="btn-focus rounded-xl border border-white/10 bg-slate-950/50 px-3 py-3 text-xs text-slate-100" disabled={!androidSerial || !!busy} onClick={() => void sendAndroidAction("rotate", { rotation: "1" })}>Landscape</button>
                    </div>
                    <div className="mt-4 grid grid-cols-2 gap-2">
                      {["up", "down", "left", "right"].map((direction) => (
                        <button key={direction} className="btn-focus rounded-xl border border-white/10 bg-slate-950/50 px-3 py-3 text-xs uppercase text-slate-100" disabled={!androidSerial || !!busy} onClick={() => void sendAndroidAction("swipe", { direction })}>Swipe {direction}</button>
                      ))}
                    </div>
                  </div>
                  <div className="rounded-3xl border border-white/8 bg-black/20 p-5">
                    <h3 className="text-base font-semibold text-white">{tr("输入与跳转", "Input and Launch")}</h3>
                    <textarea className="mt-4 min-h-[6rem] w-full rounded-2xl border border-white/10 bg-black/45 p-4 text-sm text-slate-200" placeholder={tr("输入要发送到安卓输入框的文字", "Text to send to Android")} value={androidText} onChange={(event) => setAndroidText(event.target.value)} />
                    <Button className="mt-3 bg-cyan-600" disabled={!androidText.trim() || !androidSerial || !!busy} onClick={() => void sendAndroidAction("text", { text: androidText })}>{tr("发送文本", "Send Text")}</Button>
                    <input className="mt-4 w-full rounded-2xl border border-white/10 bg-black/45 px-4 py-3 text-sm text-slate-200" placeholder="com.zhiliaoapp.musically" value={androidPackage} onChange={(event) => setAndroidPackage(event.target.value)} />
                    <div className="mt-3 grid grid-cols-3 gap-2">
                      <Button className="bg-emerald-600" disabled={!androidPackage.trim() || !androidSerial || !!busy} onClick={() => void sendAndroidAction("launch_package", { package: androidPackage })}>{tr("启动", "Launch")}</Button>
                      <Button className="bg-amber-600" disabled={!androidPackage.trim() || !androidSerial || !!busy} onClick={() => void sendAndroidAction("force_stop", { package: androidPackage })}>{tr("停应用", "Stop App")}</Button>
                      <Button className="bg-rose-600" disabled={!androidPackage.trim() || !androidSerial || !!busy} onClick={() => void sendAndroidAction("clear_app", { package: androidPackage })}>{tr("清数据", "Clear Data")}</Button>
                    </div>
                    <input className="mt-4 w-full rounded-2xl border border-white/10 bg-black/45 px-4 py-3 text-sm text-slate-200" placeholder="https://www.tiktok.com" value={androidUrl} onChange={(event) => setAndroidUrl(event.target.value)} />
                    <Button className="mt-3 bg-violet-600" disabled={!androidUrl.trim() || !androidSerial || !!busy} onClick={() => void sendAndroidAction("open_url", { url: androidUrl })}>{tr("打开链接", "Open URL")}</Button>
                  </div>
                  <div className="rounded-3xl border border-white/8 bg-black/20 p-5">
                    <div className="flex items-center justify-between gap-3">
                      <h3 className="text-base font-semibold text-white">{tr("应用工作台", "App Workspace")}</h3>
                      <Button className="border border-white/12 bg-black/20" disabled={!androidSerial || !!busy} onClick={() => void refreshAndroidUi(androidSerial)}>{tr("刷新UI", "Refresh UI")}</Button>
                    </div>
                    <div className="mt-4 flex flex-wrap gap-2">
                      {[
                        ["TikTok", "com.zhiliaoapp.musically"],
                        ["Chrome", "com.android.chrome"],
                        ["Settings", "com.android.settings"],
                        ["YouTube", "com.google.android.youtube"],
                        ["Play", "com.android.vending"],
                      ].map(([label, pkg]) => (
                        <button key={pkg} className="btn-focus rounded-xl border border-white/10 bg-slate-950/50 px-3 py-2 text-xs text-slate-100" disabled={!androidSerial || !!busy} onClick={() => { setAndroidPackage(pkg); void sendAndroidAction("launch_package", { package: pkg }); }}>
                          {label}
                        </button>
                      ))}
                    </div>
                    <div className="mt-4 flex gap-2">
                      <input className="w-full rounded-2xl border border-white/10 bg-black/45 px-4 py-3 text-sm text-slate-200" placeholder={tr("搜索包名，例如 tiktok", "Search package, e.g. tiktok")} value={androidPackageQuery} onChange={(event) => setAndroidPackageQuery(event.target.value)} />
                      <Button className="bg-cyan-600" disabled={!androidSerial || !!busy} onClick={() => void refreshAndroidPackages(androidSerial)}>{tr("搜索", "Search")}</Button>
                    </div>
                    <div className="mt-4 space-y-2">
                      {androidPackages.length === 0 ? (
                        <div className="rounded-2xl border border-dashed border-white/10 px-4 py-6 text-sm text-slate-500">{tr("还没有查询结果。", "No package results yet.")}</div>
                      ) : (
                        androidPackages.slice(0, 8).map((item) => (
                          <div key={item.package} className="rounded-2xl border border-white/8 bg-slate-950/30 p-3">
                            <div className="text-sm text-white">{item.label || item.package.split(".").pop()}</div>
                            <div className="mt-1 truncate font-mono text-[11px] text-slate-500">{item.package}</div>
                            <div className="mt-3 flex flex-wrap gap-2">
                              <button className="btn-focus rounded-xl border border-white/10 px-3 py-2 text-xs text-slate-200" disabled={!androidSerial || !!busy} onClick={() => { setAndroidPackage(item.package); void sendAndroidAction("launch_package", { package: item.package }); }}>{tr("启动", "Launch")}</button>
                              <button className="btn-focus rounded-xl border border-white/10 px-3 py-2 text-xs text-slate-200" disabled={!androidSerial || !!busy} onClick={() => { setAndroidPackage(item.package); void sendAndroidAction("force_stop", { package: item.package }); }}>{tr("停应用", "Stop")}</button>
                              <button className="btn-focus rounded-xl border border-white/10 px-3 py-2 text-xs text-slate-200" disabled={!androidSerial || !!busy} onClick={() => { setAndroidPackage(item.package); void sendAndroidAction("clear_app", { package: item.package }); }}>{tr("清数据", "Clear")}</button>
                            </div>
                          </div>
                        ))
                      )}
                    </div>
                  </div>
                </div>
                <div className="mt-6 grid gap-6 xl:grid-cols-[0.95fr,1.05fr]">
                  <div className="rounded-3xl border border-white/8 bg-black/20 p-5">
                    <h3 className="text-base font-semibold text-white">ADB Shell</h3>
                    <div className="mt-4 flex flex-col gap-3 lg:flex-row">
                      <input className="w-full rounded-2xl border border-white/10 bg-black/45 px-4 py-3 text-sm text-slate-200" placeholder="input keyevent KEYCODE_HOME" value={androidShell} onChange={(event) => setAndroidShell(event.target.value)} />
                      <Button className="bg-amber-600" disabled={!androidShell.trim() || !androidSerial || !!busy} onClick={() => void sendAndroidAction("shell", { command: androidShell })}>{tr("执行命令", "Run Command")}</Button>
                    </div>
                    <pre className="log-scroll mt-4 min-h-[14rem] rounded-2xl border border-white/10 bg-black/45 p-4 font-mono text-[11px] text-slate-200">{androidOutput || tr("动作结果会显示在这里。", "Action output will appear here.")}</pre>
                  </div>
                  <div className="rounded-3xl border border-white/8 bg-black/20 p-5">
                    <div className="flex items-center justify-between gap-3">
                      <div>
                        <h3 className="text-base font-semibold text-white">{tr("UI 节点", "UI Nodes")}</h3>
                        <p className="mt-2 text-xs text-slate-400">{tr("用 uiautomator 抓当前页面结构，快速定位可点击元素。", "Inspect the current UI hierarchy and act on clickable nodes.")}</p>
                      </div>
                      <Button className="border border-white/12 bg-black/20" disabled={!androidSerial || !!busy} onClick={() => void refreshAndroidUi(androidSerial)}>{tr("刷新节点", "Refresh Nodes")}</Button>
                    </div>
                    <div className="mt-4 space-y-3">
                      {androidNodes.length === 0 ? (
                        <div className="rounded-2xl border border-dashed border-white/10 px-4 py-6 text-sm text-slate-500">{tr("还没有抓到 UI 节点。", "No UI nodes yet.")}</div>
                      ) : (
                        androidNodes.slice(0, 12).map((node, index) => (
                          <div key={`${node.resource_id || node.label}-${index}`} className="rounded-2xl border border-white/8 bg-slate-950/30 p-3">
                            <div className="flex items-start justify-between gap-3">
                              <div>
                                <div className="text-sm text-white">{node.label || node.resource_id || node.class_name || "node"}</div>
                                <div className="mt-1 text-[11px] text-slate-500">{node.resource_id || node.class_name || "-"}</div>
                                <div className="mt-1 text-[11px] text-slate-500">{node.bounds} | {node.center_x},{node.center_y}</div>
                              </div>
                              <div className="flex flex-wrap gap-2">
                                <button className="btn-focus rounded-xl border border-white/10 px-3 py-2 text-xs text-slate-200" disabled={!androidSerial || !!busy} onClick={() => void sendAndroidAction("tap", { x: node.center_x, y: node.center_y })}>{tr("点击", "Tap")}</button>
                                <button className="btn-focus rounded-xl border border-white/10 px-3 py-2 text-xs text-slate-200" disabled={!androidSerial || !!busy} onClick={() => void sendAndroidAction("long_press", { x: node.center_x, y: node.center_y, duration: 750 })}>{tr("长按", "Long Press")}</button>
                              </div>
                            </div>
                            {node.text || node.content_desc ? (
                              <div className="mt-2 whitespace-pre-wrap text-xs text-slate-400">{node.text || node.content_desc}</div>
                            ) : null}
                          </div>
                        ))
                      )}
                    </div>
                  </div>
                </div>
                {rawAndroidPanelUrl ? (
                  <div className="mt-6 rounded-3xl border border-white/8 bg-black/20 p-5">
                    <div className="flex items-center justify-between gap-3">
                      <h3 className="text-base font-semibold text-white">ws-scrcpy</h3>
                      <a className="btn-focus rounded-xl border border-white/12 px-3 py-2 text-xs text-slate-200" href={rawAndroidPanelUrl} target="_blank" rel="noreferrer">{tr("打开原始面板", "Open raw panel")}</a>
                    </div>
                    <iframe className="mt-4 h-[30rem] w-full rounded-2xl border border-white/10 bg-black" src={rawAndroidPanelUrl} title="ws-scrcpy" />
                  </div>
                ) : null}
              </article>
            </section>
          ) : null}

          {tab === "config" ? (
            <section className="grid gap-6 xl:grid-cols-12">
              <article className="glass rounded-3xl p-6 xl:col-span-4">
                <div className="flex items-center justify-between gap-3">
                  <div>
                    <h2 className="text-lg font-semibold text-white">{tr("配置中心", "Config Center")}</h2>
                    <p className="mt-2 text-xs text-slate-400">{tr("系统级与业务级配置文件分目录托管，避免大杂烩。", "System and business configs are isolated by managed roots.")}</p>
                  </div>
                  <Button className="border border-white/12 bg-black/20" onClick={() => void refreshFiles(rootId)}>{tr("刷新", "Refresh")}</Button>
                </div>
                <select className="mt-4 w-full rounded-2xl border border-white/12 bg-slate-950/60 px-4 py-3 text-sm text-white" value={rootId} onChange={(event) => { setRootId(event.target.value); setFilePath(""); }}>
                  {activeRoots.map((item) => (
                    <option key={item.root_id} value={item.root_id}>{item.label} | {item.file_count}</option>
                  ))}
                </select>
                {currentRoot ? (
                  <div className="mt-4 rounded-2xl border border-white/8 bg-black/20 p-4 text-xs text-slate-400">
                    <p className="text-white">{currentRoot.label}</p>
                    <p className="mt-2">{currentRoot.description}</p>
                    <p className="mt-2 font-mono text-[11px] text-slate-500">{currentRoot.path}</p>
                  </div>
                ) : null}
                <div className="mt-4 flex flex-wrap gap-2">
                  <Button className="bg-cyan-600" disabled={!!busy} onClick={() => void createFile()}>{tr("新建", "New")}</Button>
                  <Button className="bg-rose-600" disabled={!filePath || !!busy} onClick={() => void deleteFile()}>{tr("删除", "Delete")}</Button>
                </div>
                <div className="mt-4 space-y-2">
                  {files.map((item) => (
                    <button key={item.path} className={`btn-focus w-full rounded-2xl border px-4 py-3 text-left ${filePath === item.path ? "border-cyan-500/40 bg-cyan-500/10" : "border-white/8 bg-black/20"}`} onClick={() => setFilePath(item.path)}>
                      <div className="truncate text-sm text-white">{item.path}</div>
                      <div className="mt-1 text-[11px] text-slate-500">{formatBytes(item.size)} | {new Date(item.mtime * 1000).toLocaleString(lang === "zh" ? "zh-CN" : "en-US", { hour12: false })}</div>
                    </button>
                  ))}
                </div>
              </article>
              <article className="glass rounded-3xl p-6 xl:col-span-8">
                <div className="flex items-center justify-between gap-3">
                  <div>
                    <h2 className="text-lg font-semibold text-white">{tr("文件编辑器", "Config Editor")}</h2>
                    <p className="mt-2 text-xs text-slate-400">{tr("仅允许编辑受管目录中的配置文件。", "Only approved config roots are editable.")}</p>
                  </div>
                  <div className="flex flex-wrap gap-2">
                    <label className={`btn-focus rounded-xl border border-white/12 px-3 py-2 text-xs text-slate-100 ${busy ? "cursor-not-allowed opacity-40" : ""}`}>
                      {busy === "file:import" ? tr("导入中...", "Importing...") : tr("导入/替换", "Import/Replace")}
                      <input key={`config-${fileImportKey}`} className="hidden" disabled={!!busy} type="file" accept=".yaml,.yml,.json,.cfg,.env,.list,.txt,.ini" onChange={(event) => void importManagedFile(event)} />
                    </label>
                    <Button className="bg-cyan-600" disabled={!filePath || !!busy} onClick={() => void saveFile()}>{busy === "file:save" ? tr("保存中...", "Saving...") : tr("保存", "Save")}</Button>
                  </div>
                </div>
                <div className="mt-4 rounded-2xl border border-white/8 bg-black/20 px-4 py-3 font-mono text-[11px] text-slate-500">{filePath ? `${rootId} / ${filePath}` : tr("请选择文件", "Pick a file")}</div>
                <textarea className="log-scroll mt-4 min-h-[32rem] w-full resize-y rounded-2xl border border-white/10 bg-black/45 p-4 font-mono text-xs leading-relaxed text-slate-200" spellCheck={false} value={fileContent} onChange={(event) => setFileContent(event.target.value)} />
              </article>
            </section>
          ) : null}
        </div>
      ) : null}
    </main>

      <nav
        className="fixed bottom-0 left-0 right-0 z-40 flex justify-around border-t border-white/15 bg-black/75 py-1.5 backdrop-blur-lg [html[data-theme=light]_&]:border-slate-200/60 [html[data-theme=light]_&]:bg-white/90 md:hidden"
        style={{ paddingBottom: "max(0.35rem, env(safe-area-inset-bottom))" }}
        aria-label={tr("主导航", "Main nav")}
      >
        {TABS.map((item) => (
          <button
            key={item}
            type="button"
            className={`btn-focus flex min-w-0 flex-1 flex-col items-center gap-0.5 rounded-xl px-1 py-1 text-[10px] font-medium ${
              tab === item ? "text-cyan-300 [html[data-theme=light]_&]:text-cyan-700" : "text-slate-400 [html[data-theme=light]_&]:text-slate-600"
            }`}
            onClick={() => setTab(item)}
          >
            <span className="text-lg leading-none" aria-hidden>
              {tabEmoji[item]}
            </span>
            <span className="truncate">
              {{
                overview: tr("总览", "Home"),
                business: tr("业务", "Biz"),
                modules: tr("模块", "Mods"),
                shellcrash: "SC",
                android: tr("安卓", "Droid"),
                config: tr("配置", "Cfg"),
              }[item]}
            </span>
          </button>
        ))}
      </nav>
    </>
  );
}
