"use client";

import { invoke } from "@tauri-apps/api/core";
import { listen } from "@tauri-apps/api/event";
import { save } from "@tauri-apps/plugin-dialog";
import { writeTextFile } from "@tauri-apps/plugin-fs";
import Color from "color";
import * as React from "react";
import { useTranslation } from "react-i18next";
import { FaApple, FaLinux, FaWindows } from "react-icons/fa";
import {
  LuChevronRight,
  LuClipboard,
  LuClipboardCheck,
  LuCookie,
  LuCopy,
  LuDownload,
  LuEraser,
  LuFingerprint,
  LuGlobe,
  LuGroup,
  LuKey,
  LuLink,
  LuLock,
  LuLockOpen,
  LuPlus,
  LuPuzzle,
  LuRefreshCw,
  LuSettings,
  LuShield,
  LuShieldCheck,
  LuTimer,
  LuTrash2,
  LuUpload,
  LuUsers,
  LuX,
} from "react-icons/lu";
import { SharedFingerprintConfigForm } from "@/components/shared-fingerprint-config-form";
import { AnimatedSwitch } from "@/components/ui/animated-switch";
import { Button } from "@/components/ui/button";
import {
  ColorPicker,
  ColorPickerEyeDropper,
  ColorPickerFormat,
  ColorPickerHue,
  ColorPickerOutput,
  ColorPickerSelection,
} from "@/components/ui/color-picker";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Input } from "@/components/ui/input";
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from "@/components/ui/popover";
import { ScrollArea } from "@/components/ui/scroll-area";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import { translateBackendError } from "@/lib/backend-errors";
import { getProfileIcon } from "@/lib/browser-utils";
import { DNS_BLOCKLIST_LEVELS } from "@/lib/dns-blocklist-levels";
import { formatRelativeTime } from "@/lib/flag-utils";
import { showErrorToast, showSuccessToast } from "@/lib/toast-utils";
import { cn } from "@/lib/utils";
import type {
  BrowserProfile,
  ProfileGroup,
  StoredProxy,
  VpnConfig,
  WayfernConfig,
} from "@/types";

interface ProfileInfoDialogProps {
  isOpen: boolean;
  onClose: () => void;
  profile: BrowserProfile | null;
  storedProxies: StoredProxy[];
  vpnConfigs: VpnConfig[];
  onOpenTrafficDialog?: (profileId: string) => void;
  onOpenProfileSyncDialog?: (profile: BrowserProfile) => void;
  onAssignProfilesToGroup?: (profileIds: string[]) => void;
  onConfigureWayfern?: (profile: BrowserProfile) => void;
  onCopyCookiesToProfile?: (profile: BrowserProfile) => void;
  onOpenCookieManagement?: (profile: BrowserProfile) => void;
  onAssignExtensionGroup?: (profileIds: string[]) => void;
  onOpenBypassRules?: (profile: BrowserProfile) => void;
  onOpenDnsBlocklist?: (profile: BrowserProfile) => void;
  onOpenLaunchHook?: (profile: BrowserProfile) => void;
  onCloneProfile?: (profile: BrowserProfile) => void;
  onDeleteProfile?: (profile: BrowserProfile) => void;
  onLaunchWithSync?: (profile: BrowserProfile) => void;
  onSetPassword?: (profile: BrowserProfile) => void;
  onChangePassword?: (profile: BrowserProfile) => void;
  onRemovePassword?: (profile: BrowserProfile) => void;
  crossOsUnlocked?: boolean;
  isRunning?: boolean;
  isDisabled?: boolean;
  isCrossOs?: boolean;
  syncStatuses: Record<string, { status: string; error?: string }>;
}

function _OSIcon({ os }: { os: string }) {
  switch (os) {
    case "macos":
      return <FaApple className="size-3.5" />;
    case "windows":
      return <FaWindows className="size-3.5" />;
    case "linux":
      return <FaLinux className="size-3.5" />;
    default:
      return null;
  }
}

function ClearOnCloseToggle({
  profile,
  isDisabled,
}: {
  profile: BrowserProfile;
  isDisabled: boolean;
}) {
  const { t } = useTranslation();
  const [enabled, setEnabled] = React.useState(profile.clear_on_close === true);
  const [saving, setSaving] = React.useState(false);

  React.useEffect(() => {
    setEnabled(profile.clear_on_close === true);
  }, [profile.clear_on_close]);

  const toggle = async (next: boolean) => {
    setEnabled(next);
    setSaving(true);
    try {
      await invoke("update_profile_clear_on_close", {
        profileId: profile.id,
        clearOnClose: next,
      });
    } catch (error) {
      setEnabled(!next);
      showErrorToast(translateBackendError(t, error));
    } finally {
      setSaving(false);
    }
  };

  return (
    <div className="flex items-center gap-3 rounded-md border border-border bg-muted/40 px-3 py-2">
      <LuEraser className="size-4 shrink-0 text-muted-foreground" />
      <div className="min-w-0 flex-1">
        <p className="text-sm font-medium">{t("clearOnClose.label")}</p>
        <p className="text-[11px] text-muted-foreground">
          {t("clearOnClose.description")}
        </p>
      </div>
      <AnimatedSwitch
        checked={enabled}
        disabled={saving || isDisabled}
        onCheckedChange={(v) => void toggle(v === true)}
        aria-label={t("clearOnClose.label")}
      />
    </div>
  );
}

function InfoCard({ label, value }: { label: string; value: string }) {
  return (
    <div className="rounded-md border bg-muted/50 px-3 py-2.5">
      <p className="text-xs text-muted-foreground">{label}</p>
      <p className="mt-0.5 truncate text-sm">{value}</p>
    </div>
  );
}

function formatBytes(bytes: number): string {
  if (!Number.isFinite(bytes) || bytes <= 0) return "0 B";
  if (bytes < 1024) return `${bytes} B`;
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
  if (bytes < 1024 * 1024 * 1024)
    return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
  return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} GB`;
}

/**
 * Shows the total bytes routed through Donut's local proxy worker for this
 * profile. Only counts traffic flowing through the donut-proxy binary — not
 * the browser's full network usage, hence the "Local" qualifier.
 */
function LocalDataTransferCard({
  profileId,
  t,
}: {
  profileId: string;
  t: (key: string, options?: Record<string, unknown>) => string;
}) {
  type Snapshot = {
    total_bytes_sent: number;
    total_bytes_received: number;
  };
  const [value, setValue] = React.useState<string>("—");

  React.useEffect(() => {
    let mounted = true;
    const fetchSnapshot = async () => {
      try {
        const snap = await invoke<Snapshot | null>(
          "get_profile_traffic_snapshot",
          { profileId },
        );
        if (!mounted) return;
        if (!snap) {
          setValue("0 B");
          return;
        }
        setValue(
          formatBytes(snap.total_bytes_sent + snap.total_bytes_received),
        );
      } catch {
        if (mounted) setValue("—");
      }
    };
    void fetchSnapshot();
    const interval = window.setInterval(fetchSnapshot, 5000);
    return () => {
      mounted = false;
      window.clearInterval(interval);
    };
  }, [profileId]);

  return (
    <InfoCard label={t("profileInfo.fields.localDataTransfer")} value={value} />
  );
}

// Shown only for legacy profiles that predate the feature and have no stored
// color yet (new profiles get a backend-derived one at creation/launch).
const DEFAULT_SWATCH_COLOR = "#94a3b8";

function WindowColorSwatch({ profile }: { profile: BrowserProfile }) {
  const { t } = useTranslation();
  const [color, setColor] = React.useState(profile.window_color);

  React.useEffect(() => {
    setColor(profile.window_color);
  }, [profile.window_color]);

  const persist = React.useCallback(
    async (hex: string) => {
      try {
        await invoke("update_profile_window_color", {
          profileId: profile.id,
          windowColor: hex,
        });
      } catch {
        setColor(profile.window_color);
      }
    },
    [profile.id, profile.window_color],
  );

  return (
    <Popover
      onOpenChange={(open) => {
        if (!open && color && color !== profile.window_color)
          void persist(color);
      }}
    >
      <PopoverTrigger asChild>
        <button
          type="button"
          aria-label={t("profileInfo.fields.windowColor")}
          title={t("profileInfo.fields.windowColor")}
          className="size-9 shrink-0 cursor-pointer rounded-lg border shadow-sm ring-offset-background transition-transform hover:scale-105 focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none"
          style={{ backgroundColor: color ?? DEFAULT_SWATCH_COLOR }}
        />
      </PopoverTrigger>
      <PopoverContent align="end" sideOffset={6} className="w-[264px] p-3">
        <ColorPicker
          className="rounded-md border bg-background p-3 shadow-sm"
          value={color ?? DEFAULT_SWATCH_COLOR}
          onColorChange={([r, g, b]) => {
            setColor(Color({ r, g, b }).hex().toLowerCase());
          }}
        >
          <ColorPickerSelection className="h-32 rounded" />
          <div className="mt-3 flex items-center gap-3">
            <ColorPickerEyeDropper />
            <ColorPickerHue className="flex-1" />
          </div>
          <div className="mt-3 flex items-center gap-2">
            <ColorPickerOutput />
            <ColorPickerFormat />
          </div>
        </ColorPicker>
      </PopoverContent>
    </Popover>
  );
}

export function ProfileInfoDialog({
  isOpen,
  onClose,
  profile,
  storedProxies,
  vpnConfigs,
  onOpenTrafficDialog,
  onOpenProfileSyncDialog,
  onAssignProfilesToGroup,
  onConfigureWayfern,
  onCopyCookiesToProfile,
  onOpenCookieManagement,
  onAssignExtensionGroup,
  onOpenBypassRules,
  onOpenDnsBlocklist,
  onOpenLaunchHook,
  onCloneProfile,
  onDeleteProfile,
  onLaunchWithSync,
  onSetPassword,
  onChangePassword,
  onRemovePassword,
  crossOsUnlocked = false,
  isRunning = false,
  isDisabled = false,
  isCrossOs = false,
  syncStatuses,
}: ProfileInfoDialogProps) {
  const { t } = useTranslation();
  const [copied, setCopied] = React.useState(false);
  const [groupName, setGroupName] = React.useState<string | null>(null);
  const [extensionGroupName, setExtensionGroupName] = React.useState<
    string | null
  >(null);

  React.useEffect(() => {
    if (!isOpen || !profile?.group_id) {
      setGroupName(null);
      return;
    }
    void (async () => {
      try {
        const groups = await invoke<ProfileGroup[]>("get_groups");
        const group = groups.find((g) => g.id === profile.group_id);
        setGroupName(group?.name ?? null);
      } catch {
        setGroupName(null);
      }
    })();
  }, [isOpen, profile?.group_id]);

  React.useEffect(() => {
    if (!isOpen || !profile?.extension_group_id) {
      setExtensionGroupName(null);
      return;
    }
    void (async () => {
      try {
        const group = await invoke<{ name: string } | null>(
          "get_extension_group_for_profile",
          { profileId: profile.id },
        );
        setExtensionGroupName(group?.name ?? null);
      } catch {
        setExtensionGroupName(null);
      }
    })();
  }, [isOpen, profile?.extension_group_id, profile?.id]);

  React.useEffect(() => {
    if (!isOpen) {
      setCopied(false);
    }
  }, [isOpen]);

  if (!profile) return null;

  const ProfileIcon = getProfileIcon(profile);
  const isWayfern = profile.browser === "wayfern";
  const isDeleteDisabled = isRunning;

  const proxyName = profile.proxy_id
    ? storedProxies.find((p) => p.id === profile.proxy_id)?.name
    : null;
  const vpnName = profile.vpn_id
    ? vpnConfigs.find((v) => v.id === profile.vpn_id)?.name
    : null;
  const networkLabel = vpnName
    ? t("profileInfo.network.vpnLabel", { name: vpnName })
    : proxyName
      ? t("profileInfo.network.proxyLabel", { name: proxyName })
      : t("profileInfo.values.none");

  const syncStatus = syncStatuses[profile.id];
  const syncMode = profile.sync_mode ?? "Disabled";

  const handleCopyId = async () => {
    try {
      await navigator.clipboard.writeText(profile.id);
      setCopied(true);
      setTimeout(() => {
        setCopied(false);
      }, 2000);
    } catch {
      // ignore
    }
  };

  const handleAction = (action: () => void) => {
    onClose();
    action();
  };

  const hasTags = profile.tags && profile.tags.length > 0;
  const hasNote = !!profile.note;

  // Items in the settings tab `actions` list MUST only open another dialog
  // (or trigger a navigation/action that closes this one). Do NOT put inline
  // settings UI — inputs, toggles, save buttons — directly in this dialog's
  // settings tab. Each setting belongs in its own focused dialog (see
  // `ProfileLaunchHookDialog`, `ProfileBypassRulesDialog`,
  // `ProfileDnsBlocklistDialog` for the pattern). The settings tab is purely
  // a navigation hub.
  interface ActionItem {
    // Stable, language-independent key used to map sidebar sections to actions.
    // The sidebar must NOT match on `label` — labels are translated, so English
    // substring matching hides sections for every non-English user.
    id?: string;
    icon: React.ReactNode;
    label: string;
    onClick: () => void;
    disabled?: boolean;
    destructive?: boolean;
    proBadge?: boolean;
    runningBadge?: boolean;
    hidden?: boolean;
  }

  const actions: ActionItem[] = [
    {
      id: "network",
      icon: <LuGlobe className="size-4" />,
      label: t("profiles.actions.viewNetwork"),
      onClick: () => {
        handleAction(() => onOpenTrafficDialog?.(profile.id));
      },
      disabled: isCrossOs,
    },
    {
      id: "sync",
      icon: <LuRefreshCw className="size-4" />,
      label: t("profiles.actions.syncSettings"),
      onClick: () => {
        handleAction(() => onOpenProfileSyncDialog?.(profile));
      },
      disabled: isCrossOs,
      hidden: profile.ephemeral === true,
    },
    {
      icon: <LuGroup className="size-4" />,
      label: t("profiles.actions.assignToGroup"),
      onClick: () => {
        handleAction(() => onAssignProfilesToGroup?.([profile.id]));
      },
      disabled: isDisabled,
      runningBadge: isRunning,
    },
    {
      id: "fingerprint",
      icon: <LuFingerprint className="size-4" />,
      label: t("profiles.actions.changeFingerprint"),
      onClick: () => {
        handleAction(() => onConfigureWayfern?.(profile));
      },
      // Viewing and editing fingerprints both require an active paid plan.
      disabled: isDisabled || !crossOsUnlocked,
      proBadge: !crossOsUnlocked,
      runningBadge: isRunning,
      hidden: !isWayfern || !onConfigureWayfern,
    },
    {
      icon: <LuUsers className="size-4" />,
      label: t("profiles.synchronizer.launchWithSync"),
      onClick: () => {
        handleAction(() => onLaunchWithSync?.(profile));
      },
      disabled: isDisabled || isRunning || !crossOsUnlocked,
      proBadge: !crossOsUnlocked,
      hidden: profile.browser !== "wayfern" || !onLaunchWithSync,
    },
    {
      id: "cookiesCopy",
      icon: <LuCopy className="size-4" />,
      label: t("profiles.actions.copyCookiesToProfile"),
      onClick: () => {
        handleAction(() => onCopyCookiesToProfile?.(profile));
      },
      disabled: isDisabled,
      runningBadge: isRunning,
      hidden:
        !isWayfern || profile.ephemeral === true || !onCopyCookiesToProfile,
    },
    {
      id: "cookiesManage",
      icon: <LuCookie className="size-4" />,
      label: t("profileInfo.actions.manageCookies"),
      onClick: () => {
        handleAction(() => onOpenCookieManagement?.(profile));
      },
      disabled: isDisabled,
      runningBadge: isRunning,
      hidden:
        !isWayfern || profile.ephemeral === true || !onOpenCookieManagement,
    },
    {
      icon: <LuSettings className="size-4" />,
      label: t("profiles.actions.clone"),
      onClick: () => {
        handleAction(() => onCloneProfile?.(profile));
      },
      disabled: isDisabled,
      runningBadge: isRunning,
      hidden: profile.ephemeral === true,
    },
    {
      id: "extension",
      icon: <LuPuzzle className="size-4" />,
      label: t("profileInfo.actions.assignExtensionGroup"),
      onClick: () => {
        handleAction(() => onAssignExtensionGroup?.([profile.id]));
      },
      disabled: isDisabled,
      runningBadge: isRunning,
      hidden: profile.ephemeral === true,
    },
    {
      icon: <LuShieldCheck className="size-4" />,
      label: t("profileInfo.network.bypassRulesTitle"),
      onClick: () => {
        handleAction(() => onOpenBypassRules?.(profile));
      },
    },
    {
      icon: <LuShield className="size-4" />,
      label: t("dnsBlocklist.title"),
      onClick: () => {
        handleAction(() => onOpenDnsBlocklist?.(profile));
      },
    },
    {
      id: "hook",
      icon: <LuLink className="size-4" />,
      label: t("profiles.actions.launchHook"),
      onClick: () => {
        handleAction(() => onOpenLaunchHook?.(profile));
      },
      hidden: !onOpenLaunchHook,
    },
    {
      icon: <LuKey className="size-4" />,
      label: t("profiles.actions.setPassword"),
      onClick: () => {
        handleAction(() => onSetPassword?.(profile));
      },
      disabled: isDisabled || isRunning,
      runningBadge: isRunning,
      hidden:
        profile.password_protected === true ||
        profile.ephemeral === true ||
        !onSetPassword,
    },
    {
      icon: <LuKey className="size-4" />,
      label: t("profiles.actions.changePassword"),
      onClick: () => {
        handleAction(() => onChangePassword?.(profile));
      },
      disabled: isDisabled || isRunning,
      runningBadge: isRunning,
      hidden: profile.password_protected !== true || !onChangePassword,
    },
    {
      icon: <LuLockOpen className="size-4" />,
      label: t("profiles.actions.removePassword"),
      onClick: () => {
        handleAction(() => onRemovePassword?.(profile));
      },
      disabled: isDisabled || isRunning,
      runningBadge: isRunning,
      hidden: profile.password_protected !== true || !onRemovePassword,
      destructive: true,
    },
    {
      id: "delete",
      icon: <LuTrash2 className="size-4" />,
      label: t("profiles.actions.delete"),
      onClick: () => {
        handleAction(() => onDeleteProfile?.(profile));
      },
      disabled: isDeleteDisabled,
      destructive: true,
    },
  ];

  const visibleActions = actions.filter((a) => !a.hidden);

  return (
    <Dialog
      open={isOpen}
      onOpenChange={(open) => {
        if (!open) onClose();
      }}
    >
      <DialogContent
        hideClose
        className="flex h-[min(clamp(30rem,80vh,48rem),calc(100vh-3rem))] max-w-[min(60rem,calc(100%-4rem))] flex-col gap-0 overflow-hidden p-0"
      >
        {/* The dialog renders its own custom header, so the accessible title is
            visually hidden but present for screen readers (Radix requires it). */}
        <DialogTitle className="sr-only">{t("profileInfo.title")}</DialogTitle>
        <ProfileInfoLayout
          profile={profile}
          ProfileIcon={ProfileIcon}
          isRunning={isRunning}
          isDisabled={isDisabled}
          networkLabel={networkLabel}
          groupName={groupName}
          extensionGroupName={extensionGroupName}
          syncMode={syncMode}
          syncStatus={syncStatus}
          storedProxies={storedProxies}
          vpnConfigs={vpnConfigs}
          hasTags={hasTags}
          hasNote={hasNote}
          copied={copied}
          handleCopyId={handleCopyId}
          onClose={onClose}
          onCloneProfile={onCloneProfile}
          onKillProfile={undefined}
          visibleActions={visibleActions}
          t={t}
        />
      </DialogContent>
    </Dialog>
  );
}

interface ProfileInfoLayoutProps {
  profile: BrowserProfile;
  ProfileIcon: React.ComponentType<{ className?: string }>;
  isRunning: boolean;
  isDisabled: boolean;
  networkLabel: string;
  groupName: string | null;
  extensionGroupName: string | null;
  syncMode: string;
  syncStatus: { status: string; error?: string } | undefined;
  hasTags: boolean | undefined;
  hasNote: boolean;
  copied: boolean;
  storedProxies: StoredProxy[];
  vpnConfigs: VpnConfig[];
  handleCopyId: () => Promise<void>;
  onClose: () => void;
  onCloneProfile?: (profile: BrowserProfile) => void;
  onKillProfile?: (profile: BrowserProfile) => void;
  visibleActions: {
    id?: string;
    icon: React.ReactNode;
    label: string;
    onClick: () => void;
    disabled?: boolean;
    destructive?: boolean;
    proBadge?: boolean;
    runningBadge?: boolean;
  }[];
  t: (key: string, options?: Record<string, unknown>) => string;
}

type ProfileSection =
  | "overview"
  | "fingerprint"
  | "network"
  | "cookies"
  | "extensions"
  | "sync"
  | "automation"
  | "security"
  | "delete";

function ProfileInfoLayout({
  profile,
  ProfileIcon,
  isRunning,
  isDisabled,
  networkLabel,
  groupName,
  extensionGroupName,
  syncMode,
  syncStatus,
  storedProxies,
  vpnConfigs,
  hasTags,
  hasNote,
  copied,
  handleCopyId,
  onClose,
  onCloneProfile,
  visibleActions,
  t,
}: ProfileInfoLayoutProps) {
  const [section, setSection] = React.useState<ProfileSection>("overview");

  // Map sidebar items to existing actions by their stable, language-independent
  // `id`, so clicking a section triggers the existing dialog handler. Matching
  // on `label` would break for every non-English locale (the labels are
  // translated) and hide whole sections.
  const findAction = React.useCallback(
    (id: string) => visibleActions.find((a) => a.id === id),
    [visibleActions],
  );

  // An ephemeral profile is discarded when the browser closes, so it has
  // nowhere to keep cookies, extensions or a synced copy. The sections were
  // hidden outright, which left no way to discover that and read as the app
  // being broken or the plan lacking the feature. Keep them listed and explain.
  const isEphemeral = profile.ephemeral === true;
  const isWayfernProfile = profile.browser === "wayfern";

  const deleteAction = findAction("delete");
  const fingerprintAction = findAction("fingerprint");
  const cookiesManageAction = findAction("cookiesManage");
  const cookiesCopyAction = findAction("cookiesCopy");
  const cookiesAction = cookiesManageAction ?? cookiesCopyAction;
  const extensionAction = findAction("extension");
  const syncAction = findAction("sync");
  const _launchHookAction = findAction("hook");
  const _networkAction = findAction("network");
  // Password actions are no longer routed via the legacy action handlers —
  // SecuritySectionInline writes directly to the backend instead.

  // Cookie count is fetched at the layout level so the sidebar badge can
  // surface it without waiting for the user to open the Cookies section.
  // The effect deps must be primitive — `cookiesAction` is a new object
  // every render and using it directly here caused an infinite re-render
  // loop that froze the entire app when the dialog opened.
  // Skipped while running: the cookie DB is held by the browser and we
  // don't want to compete for its lock from the badge fetch.
  const cookiesSupported = !!cookiesAction;
  const [cookieCount, setCookieCount] = React.useState<number | null>(null);
  React.useEffect(() => {
    if (!cookiesSupported || isRunning) {
      setCookieCount(null);
      return;
    }
    let mounted = true;
    void (async () => {
      try {
        const data = await invoke<{ total_count: number }>(
          "get_profile_cookie_stats",
          { profileId: profile.id },
        );
        if (mounted) setCookieCount(data.total_count);
      } catch {
        if (mounted) setCookieCount(null);
      }
    })();
    return () => {
      mounted = false;
    };
  }, [profile.id, cookiesSupported, isRunning]);

  const sidebarItems: {
    id: ProfileSection;
    icon: React.ReactNode;
    label: string;
    badge?: string;
    destructive?: boolean;
    hidden?: boolean;
  }[] = [
    {
      id: "overview",
      icon: <LuClipboard className="size-3.5" />,
      label: t("profileInfo.sections.overview"),
    },
    {
      id: "fingerprint",
      icon: <LuFingerprint className="size-3.5" />,
      label: t("profileInfo.sections.fingerprint"),
      badge: profile.password_protected
        ? t("profileInfo.badges.locked")
        : undefined,
      hidden: !fingerprintAction,
    },
    {
      id: "network",
      icon: <LuGlobe className="size-3.5" />,
      label: t("profileInfo.sections.network"),
      badge: profile.proxy_id || profile.vpn_id ? networkLabel : undefined,
    },
    {
      id: "cookies",
      icon: <LuCookie className="size-3.5" />,
      label: t("profileInfo.sections.cookies"),
      badge:
        cookieCount !== null && cookieCount > 0
          ? cookieCount.toLocaleString()
          : undefined,
      hidden: !cookiesAction && !(isEphemeral && isWayfernProfile),
    },
    {
      id: "extensions",
      icon: <LuPuzzle className="size-3.5" />,
      label: t("profileInfo.sections.extensions"),
      badge: extensionGroupName ?? undefined,
      hidden: !extensionAction && !isEphemeral,
    },
    {
      id: "sync",
      icon: <LuRefreshCw className="size-3.5" />,
      label: t("profileInfo.sections.sync"),
      hidden: !syncAction && !isEphemeral,
    },
    {
      id: "automation",
      icon: <LuLink className="size-3.5" />,
      label: t("profileInfo.sections.launchHook"),
      badge: profile.launch_hook ? t("profileInfo.badges.active") : undefined,
    },
    {
      id: "security",
      icon: <LuKey className="size-3.5" />,
      label: t("profileInfo.sections.security"),
    },
  ];

  return (
    <>
      {/* Top bar */}
      <div className="flex h-11 shrink-0 items-center gap-2 border-b border-border px-3">
        <LuUsers className="size-3.5 shrink-0 text-muted-foreground" />
        <div className="flex min-w-0 flex-1 items-center gap-1.5 text-xs">
          <span className="font-semibold">
            {t("profileInfo.breadcrumbRoot")}
          </span>
          <span className="text-muted-foreground">/</span>
          <span className="truncate text-muted-foreground">{profile.name}</span>
        </div>
        {onCloneProfile && (
          <Button
            variant="ghost"
            size="sm"
            className="h-7 gap-1.5 px-2 text-xs"
            disabled={isDisabled}
            onClick={() => onCloneProfile(profile)}
          >
            <LuCopy className="size-3" />
            {t("profileInfo.duplicate")}
          </Button>
        )}
        <button
          type="button"
          aria-label={t("common.buttons.close")}
          onClick={onClose}
          className="grid size-7 place-items-center rounded-md text-muted-foreground transition-colors duration-100 hover:bg-accent hover:text-accent-foreground"
        >
          <LuX className="size-3.5" />
        </button>
      </div>

      {/* Body */}
      <div className="flex min-h-0 flex-1">
        {/* Sidebar */}
        <nav className="flex w-44 shrink-0 flex-col gap-0.5 overflow-y-auto border-r border-border p-2">
          {sidebarItems
            .filter((it) => !it.hidden)
            .map((it) => {
              const active = section === it.id;
              return (
                <button
                  key={it.id}
                  type="button"
                  onClick={() => setSection(it.id)}
                  className={cn(
                    "flex h-7 items-center gap-2 rounded-md px-2 text-left text-xs transition-colors duration-100",
                    active
                      ? "bg-accent text-accent-foreground"
                      : "text-muted-foreground hover:bg-accent hover:text-accent-foreground",
                  )}
                >
                  <span className="shrink-0">{it.icon}</span>
                  <span className="flex-1 truncate">{it.label}</span>
                  {it.badge && (
                    <span className="max-w-[60px] truncate text-[9px] tracking-wide text-muted-foreground uppercase">
                      {it.badge}
                    </span>
                  )}
                </button>
              );
            })}
          {deleteAction && (
            <>
              <div className="my-1 h-px bg-border" />
              <button
                type="button"
                onClick={deleteAction.onClick}
                disabled={deleteAction.disabled}
                className="flex h-7 items-center gap-2 rounded-md px-2 text-xs text-destructive-text transition-colors duration-100 hover:bg-destructive/10 disabled:pointer-events-none disabled:opacity-50"
              >
                <LuTrash2 className="size-3.5 shrink-0" />
                <span className="flex-1 text-left">
                  {t("profileInfo.sections.delete")}
                </span>
              </button>
            </>
          )}
        </nav>

        {/* Main */}
        <div className="scroll-fade min-w-0 flex-1 overflow-y-auto p-4">
          {section === "overview" && (
            <div className="flex flex-col gap-3">
              {/* Hero */}
              <div className="flex items-center gap-3">
                <div className="shrink-0 rounded-lg bg-muted p-2.5">
                  <ProfileIcon className="size-7 text-foreground" />
                </div>
                <div className="min-w-0 flex-1">
                  <div className="flex items-center gap-1.5">
                    <h3 className="truncate text-base font-semibold">
                      {profile.name}
                    </h3>
                  </div>
                  <div className="mt-1 flex flex-wrap items-center gap-1.5 text-[11px]">
                    <span className="font-mono text-muted-foreground">
                      {profile.version}
                    </span>
                  </div>
                </div>
                <WindowColorSwatch profile={profile} />
              </div>

              {/* ID */}
              <div className="flex items-center gap-2 rounded-md border border-border bg-muted/40 px-3 py-2">
                <span className="shrink-0 text-[10px] tracking-wide text-muted-foreground uppercase">
                  ID
                </span>
                <span className="flex-1 truncate font-mono text-xs">
                  {profile.id}
                </span>
                <button
                  type="button"
                  onClick={() => void handleCopyId()}
                  className="shrink-0 text-muted-foreground transition-colors hover:text-foreground"
                  aria-label={t("common.buttons.copy")}
                >
                  {copied ? (
                    <LuClipboardCheck className="size-3.5" />
                  ) : (
                    <LuClipboard className="size-3.5" />
                  )}
                </button>
              </div>

              {/* 2x2 cards */}
              <div className="grid grid-cols-2 gap-2">
                <InfoCard
                  label={t("profileInfo.fields.group")}
                  value={groupName ?? t("profileInfo.values.none")}
                />
                <InfoCard
                  label={t("profileInfo.fields.proxyVpn")}
                  value={networkLabel}
                />
                <InfoCard
                  label={t("profileInfo.fields.tags")}
                  value={
                    hasTags
                      ? (profile.tags ?? []).join(", ")
                      : t("profileInfo.values.none")
                  }
                />
                <InfoCard
                  label={t("profileInfo.fields.note")}
                  value={
                    hasNote
                      ? (profile.note ?? "")
                      : t("profileInfo.values.none")
                  }
                />
              </div>

              {/* Activity */}
              <div className="mt-1 flex flex-col gap-1.5">
                <span className="text-[10px] tracking-wide text-muted-foreground uppercase">
                  {t("profileInfo.sections.activity")}
                </span>
                <div className="grid grid-cols-2 gap-2">
                  <InfoCard
                    label={t("profileInfo.fields.created")}
                    value={
                      profile.created_at
                        ? new Date(profile.created_at * 1000).toLocaleString(
                            undefined,
                            { dateStyle: "medium", timeStyle: "short" },
                          )
                        : t("profileInfo.values.unknown")
                    }
                  />
                  <InfoCard
                    label={t("profileInfo.fields.lastLaunched")}
                    value={
                      isRunning
                        ? t("profileInfo.values.activeNow")
                        : profile.last_launch
                          ? formatRelativeTime(profile.last_launch)
                          : t("profileInfo.values.never")
                    }
                  />
                  <LocalDataTransferCard profileId={profile.id} t={t} />
                </div>
              </div>

              {!profile.ephemeral && !profile.password_protected && (
                <ClearOnCloseToggle profile={profile} isDisabled={isDisabled} />
              )}

              {profile.created_by_email && (
                <div className="rounded-md border border-border bg-muted/40 px-3 py-2">
                  <p className="text-[10px] tracking-wide text-muted-foreground uppercase">
                    {t("sync.team.title")}
                  </p>
                  <p className="mt-0.5 text-sm">
                    {t("sync.team.createdBy", {
                      email: profile.created_by_email,
                    })}
                  </p>
                </div>
              )}
            </div>
          )}

          {section === "fingerprint" && (
            <FingerprintSectionInline
              profile={profile}
              isDisabled={isDisabled}
              crossOsUnlocked={Boolean(
                // Re-derive: parent passes crossOsUnlocked but the layout
                // doesn't get it; we get it implicitly via fingerprintAction's
                // proBadge state. Default to false if action missing.
                fingerprintAction && !fingerprintAction.proBadge,
              )}
              onSaved={onClose}
              t={t}
            />
          )}

          {section === "network" && (
            <NetworkSectionInline
              profile={profile}
              storedProxies={storedProxies}
              vpnConfigs={vpnConfigs}
              isDisabled={isDisabled}
              t={t}
            />
          )}

          {section === "cookies" &&
            (isEphemeral ? (
              <EphemeralSectionNotice
                title={t("profileInfo.sections.cookies")}
                description={t("profileInfo.ephemeral.cookiesUnavailable")}
                t={t}
              />
            ) : (
              <CookiesSectionInline
                profile={profile}
                isRunning={isRunning}
                isDisabled={isDisabled}
                onCopyCookies={cookiesCopyAction?.onClick}
                onImportCookies={cookiesManageAction?.onClick}
                t={t}
              />
            ))}

          {section === "extensions" &&
            (isEphemeral ? (
              <EphemeralSectionNotice
                title={t("profileInfo.sections.extensions")}
                description={t("profileInfo.ephemeral.extensionsUnavailable")}
                t={t}
              />
            ) : (
              <ExtensionsSectionInline
                profile={profile}
                isDisabled={isDisabled}
                t={t}
              />
            ))}

          {section === "sync" &&
            (isEphemeral ? (
              <EphemeralSectionNotice
                title={t("profileInfo.sections.sync")}
                description={t("profileInfo.ephemeral.syncUnavailable")}
                t={t}
              />
            ) : (
              <SyncSectionInline
                profile={profile}
                syncMode={syncMode}
                syncStatus={syncStatus}
                isDisabled={isDisabled}
                t={t}
              />
            ))}

          {section === "automation" && (
            <LaunchHookEditor profile={profile} t={t} />
          )}

          {section === "security" && (
            <SecuritySectionInline
              profile={profile}
              isRunning={isRunning}
              t={t}
            />
          )}
        </div>
      </div>
    </>
  );
}

function _SectionPlaceholder({
  icon,
  title,
  description,
  actionLabel,
  onAction,
  disabled,
  hint,
}: {
  icon: React.ReactNode;
  title: string;
  description: string;
  actionLabel: string;
  onAction: () => void;
  disabled?: boolean;
  hint?: string;
}) {
  return (
    <div className="flex flex-col gap-3">
      <div className="flex items-center gap-2 text-sm font-semibold">
        {icon}
        {title}
      </div>
      <p className="text-xs text-muted-foreground">{description}</p>
      {hint && (
        <div className="rounded-md border border-border bg-muted/40 px-3 py-2 text-xs">
          {hint}
        </div>
      )}
      <Button
        size="sm"
        onClick={onAction}
        disabled={disabled}
        className="h-7 self-start text-xs"
      >
        {actionLabel}
      </Button>
    </div>
  );
}

function _SectionAction({
  icon,
  label,
  onClick,
  disabled,
  destructive,
}: {
  icon: React.ReactNode;
  label: string;
  onClick: () => void;
  disabled?: boolean;
  destructive?: boolean;
}) {
  return (
    <button
      type="button"
      disabled={disabled}
      onClick={onClick}
      className={cn(
        "flex h-9 items-center gap-2 rounded-md px-3 text-left text-xs transition-colors",
        destructive
          ? "text-destructive-text hover:bg-destructive/10"
          : "hover:bg-accent hover:text-accent-foreground",
        "disabled:pointer-events-none disabled:opacity-50",
      )}
    >
      {icon}
      <span className="flex-1">{label}</span>
      <LuChevronRight className="size-3.5 text-muted-foreground" />
    </button>
  );
}

function isValidHttpUrl(value: string): boolean {
  const trimmed = value.trim();
  if (!trimmed) return false;
  try {
    const u = new URL(trimmed);
    return u.protocol === "http:" || u.protocol === "https:";
  } catch {
    return false;
  }
}

function LaunchHookEditor({
  profile,
  t,
}: {
  profile: BrowserProfile;
  t: (key: string, options?: Record<string, unknown>) => string;
}) {
  const { t: tFn } = useTranslation();
  const [value, setValue] = React.useState(profile.launch_hook ?? "");
  const [isSaving, setIsSaving] = React.useState(false);
  const [error, setError] = React.useState<string | null>(null);
  const initial = profile.launch_hook ?? "";
  const dirty = value !== initial;
  const trimmed = value.trim();
  const showInvalidHint = trimmed.length > 0 && !isValidHttpUrl(trimmed);

  const onSave = async () => {
    setIsSaving(true);
    setError(null);
    try {
      await invoke("update_profile_launch_hook", {
        profileId: profile.id,
        launchHook: trimmed ? trimmed : null,
      });
    } catch (e) {
      setError(translateBackendError(tFn, e));
    } finally {
      setIsSaving(false);
    }
  };

  return (
    <div className="flex flex-col gap-3">
      <div className="flex items-center gap-2 text-sm font-semibold">
        <LuLink className="size-4" />
        {t("profileInfo.sections.launchHook")}
      </div>
      <p className="text-xs text-muted-foreground">
        {t("profileInfo.sectionDesc.launchHook")}
      </p>
      <Input
        type="url"
        value={value}
        onChange={(e) => {
          setValue(e.target.value);
        }}
        placeholder={t("profiles.launchHook.placeholder")}
        className="font-mono text-xs"
      />
      {showInvalidHint && (
        <p className="text-xs text-warning-text">
          {t("profileInfo.launchHook.invalidUrlHint")}
        </p>
      )}
      {error && <p className="text-xs text-destructive-text">{error}</p>}
      <div className="flex items-center gap-2">
        <Button
          size="sm"
          className="h-7 text-xs"
          disabled={!dirty || isSaving || showInvalidHint}
          onClick={() => {
            void onSave();
          }}
        >
          {isSaving ? t("common.buttons.saving") : t("common.buttons.save")}
        </Button>
        {dirty && (
          <Button
            size="sm"
            variant="ghost"
            className="h-7 text-xs"
            onClick={() => {
              setValue(initial);
              setError(null);
            }}
          >
            {t("common.buttons.cancel")}
          </Button>
        )}
      </div>
    </div>
  );
}

function SyncSectionInline({
  profile,
  syncMode,
  syncStatus,
  isDisabled,
  t,
}: {
  profile: BrowserProfile;
  syncMode: string;
  syncStatus: { status: string; error?: string } | undefined;
  isDisabled: boolean;
  t: (key: string, options?: Record<string, unknown>) => string;
}) {
  const [isSaving, setIsSaving] = React.useState(false);
  const [error, setError] = React.useState<string | null>(null);

  const onChangeMode = async (mode: string) => {
    setIsSaving(true);
    setError(null);
    try {
      await invoke("set_profile_sync_mode", {
        profileId: profile.id,
        syncMode: mode,
      });
    } catch (e) {
      setError(translateBackendError(t as never, e));
    } finally {
      setIsSaving(false);
    }
  };

  return (
    <div className="flex flex-col gap-3">
      <div className="flex items-center gap-2 text-sm font-semibold">
        <LuRefreshCw className="size-4" />
        {t("profileInfo.sections.sync")}
      </div>
      <p className="text-xs text-muted-foreground">
        {t("profileInfo.sectionDesc.sync")}
      </p>
      <div className="flex items-center gap-2">
        <span className="shrink-0 text-[10px] tracking-wide text-muted-foreground uppercase">
          {t("profileInfo.fields.syncMode")}
        </span>
        <Select
          value={syncMode}
          disabled={isDisabled || isSaving}
          onValueChange={(v) => {
            void onChangeMode(v);
          }}
        >
          <SelectTrigger className="h-7 flex-1 text-xs">
            <SelectValue />
          </SelectTrigger>
          <SelectContent>
            <SelectItem value="Disabled">{t("sync.mode.disabled")}</SelectItem>
            <SelectItem value="Regular">{t("sync.mode.regular")}</SelectItem>
            <SelectItem value="Encrypted">
              {t("sync.mode.encrypted")}
            </SelectItem>
          </SelectContent>
        </Select>
      </div>
      {syncStatus && (
        <div className="rounded-md border border-border bg-muted/40 px-3 py-2">
          <p className="text-[10px] tracking-wide text-muted-foreground uppercase">
            {t("profileInfo.fields.syncStatus")}
          </p>
          <p className="mt-0.5 text-sm">
            {t(`profileInfo.syncStatusValue.${syncStatus.status}`)}
          </p>
          {syncStatus.error && (
            <p className="mt-1 text-xs text-destructive-text">
              {syncStatus.error}
            </p>
          )}
        </div>
      )}
      {error && <p className="text-xs text-destructive-text">{error}</p>}
    </div>
  );
}

function NetworkSectionInline({
  profile,
  storedProxies,
  vpnConfigs,
  isDisabled,
  t,
}: {
  profile: BrowserProfile;
  storedProxies: StoredProxy[];
  vpnConfigs: VpnConfig[];
  isDisabled: boolean;
  t: (key: string, options?: Record<string, unknown>) => string;
}) {
  const [isSaving, setIsSaving] = React.useState(false);
  const [error, setError] = React.useState<string | null>(null);
  // Track the effective selection so the dropdown reflects the last save
  // even before the parent `profile` prop refreshes from a backend event.
  const [proxyId, setProxyId] = React.useState<string | null>(
    profile.proxy_id ?? null,
  );
  const [vpnId, setVpnId] = React.useState<string | null>(
    profile.vpn_id ?? null,
  );

  React.useEffect(() => {
    setProxyId(profile.proxy_id ?? null);
    setVpnId(profile.vpn_id ?? null);
  }, [profile.proxy_id, profile.vpn_id]);

  const onProxyChange = async (value: string) => {
    const nextId = value === "__none__" ? null : value;
    setIsSaving(true);
    setError(null);
    try {
      await invoke("update_profile_proxy", {
        profileId: profile.id,
        proxyId: nextId,
      });
      // Clearing the proxy implicitly clears any VPN binding too on the
      // backend, but we mirror it locally for an immediate visual.
      setProxyId(nextId);
      if (nextId !== null) setVpnId(null);
    } catch (e) {
      setError(translateBackendError(t as never, e));
    } finally {
      setIsSaving(false);
    }
  };

  const onVpnChange = async (value: string) => {
    const nextId = value === "__none__" ? null : value;
    setIsSaving(true);
    setError(null);
    try {
      await invoke("update_profile_vpn", {
        profileId: profile.id,
        vpnId: nextId,
      });
      setVpnId(nextId);
      if (nextId !== null) setProxyId(null);
    } catch (e) {
      setError(translateBackendError(t as never, e));
    } finally {
      setIsSaving(false);
    }
  };

  return (
    <div className="flex flex-col gap-3">
      <div className="flex items-center gap-2 text-sm font-semibold">
        <LuGlobe className="size-4" />
        {t("profileInfo.sections.network")}
      </div>
      <p className="text-xs text-muted-foreground">
        {t("profileInfo.sectionDesc.network")}
      </p>

      <div className="flex items-center gap-2">
        <span className="w-12 shrink-0 text-[10px] tracking-wide text-muted-foreground uppercase">
          {t("profileInfo.fields.proxy")}
        </span>
        <Select
          value={proxyId ?? "__none__"}
          disabled={isDisabled || isSaving}
          onValueChange={(v) => {
            void onProxyChange(v);
          }}
        >
          <SelectTrigger className="h-7 flex-1 text-xs">
            <SelectValue />
          </SelectTrigger>
          <SelectContent>
            <SelectItem value="__none__">
              {t("profileInfo.values.none")}
            </SelectItem>
            {storedProxies.map((p) => (
              <SelectItem key={p.id} value={p.id}>
                {p.name}
              </SelectItem>
            ))}
          </SelectContent>
        </Select>
      </div>

      <div className="flex items-center gap-2">
        <span className="w-12 shrink-0 text-[10px] tracking-wide text-muted-foreground uppercase">
          {t("profileInfo.fields.vpn")}
        </span>
        <Select
          value={vpnId ?? "__none__"}
          disabled={isDisabled || isSaving}
          onValueChange={(v) => {
            void onVpnChange(v);
          }}
        >
          <SelectTrigger className="h-7 flex-1 text-xs">
            <SelectValue />
          </SelectTrigger>
          <SelectContent>
            <SelectItem value="__none__">
              {t("profileInfo.values.none")}
            </SelectItem>
            {vpnConfigs.map((v) => (
              <SelectItem key={v.id} value={v.id}>
                {v.name}
              </SelectItem>
            ))}
          </SelectContent>
        </Select>
      </div>

      {error && <p className="text-xs text-destructive-text">{error}</p>}
    </div>
  );
}

/// Explains why a section has nothing to offer on an ephemeral profile.
/// Mirrors the locked-fingerprint empty state so the two read as one pattern.
function EphemeralSectionNotice({
  title,
  description,
  t,
}: {
  title: string;
  description: string;
  t: (key: string, options?: Record<string, unknown>) => string;
}) {
  return (
    <div className="flex flex-col items-center gap-3 rounded-lg border p-6 text-center">
      <LuTimer className="size-4 shrink-0 text-muted-foreground" />
      <h3 className="text-sm font-medium text-foreground">{title}</h3>
      <p className="max-w-[48ch] text-sm text-pretty text-muted-foreground">
        {description}
      </p>
      <p className="max-w-[48ch] text-xs text-pretty text-muted-foreground">
        {t("profileInfo.ephemeral.hint")}
      </p>
    </div>
  );
}

function ExtensionsSectionInline({
  profile,
  isDisabled,
  t,
}: {
  profile: BrowserProfile;
  isDisabled: boolean;
  t: (key: string, options?: Record<string, unknown>) => string;
}) {
  type ExtensionGroupOption = { id: string; name: string };
  const [groups, setGroups] = React.useState<ExtensionGroupOption[]>([]);
  const [groupId, setGroupId] = React.useState<string | null>(
    profile.extension_group_id ?? null,
  );
  const [isSaving, setIsSaving] = React.useState(false);
  const [error, setError] = React.useState<string | null>(null);

  React.useEffect(() => {
    setGroupId(profile.extension_group_id ?? null);
  }, [profile.extension_group_id]);

  React.useEffect(() => {
    let mounted = true;
    let unlisten: (() => void) | undefined;
    const load = async () => {
      try {
        const data = await invoke<ExtensionGroupOption[]>(
          "list_extension_groups",
        );
        if (mounted) setGroups(data);
      } catch (e) {
        if (mounted) setError(translateBackendError(t as never, e));
      }
    };
    void load();
    void listen("extensions-changed", () => {
      void load();
    }).then((u) => {
      if (mounted) unlisten = u;
      else u();
    });
    return () => {
      mounted = false;
      unlisten?.();
    };
  }, [t]);

  const onChange = async (value: string) => {
    const next = value === "__none__" ? null : value;
    setIsSaving(true);
    setError(null);
    try {
      await invoke("assign_extension_group_to_profile", {
        profileId: profile.id,
        extensionGroupId: next,
      });
      setGroupId(next);
    } catch (e) {
      setError(translateBackendError(t as never, e));
    } finally {
      setIsSaving(false);
    }
  };

  return (
    <div className="flex flex-col gap-3">
      <div className="flex items-center gap-2 text-sm font-semibold">
        <LuPuzzle className="size-4" />
        {t("profileInfo.sections.extensions")}
      </div>
      <p className="text-xs text-muted-foreground">
        {t("profileInfo.sectionDesc.extensions")}
      </p>
      <div className="flex items-center gap-2">
        <span className="w-16 shrink-0 text-[10px] tracking-wide text-muted-foreground uppercase">
          {t("profileInfo.fields.extensionGroup")}
        </span>
        <Select
          value={groupId ?? "__none__"}
          disabled={isDisabled || isSaving}
          onValueChange={(v) => {
            void onChange(v);
          }}
        >
          <SelectTrigger className="h-7 flex-1 text-xs">
            <SelectValue />
          </SelectTrigger>
          <SelectContent>
            <SelectItem value="__none__">
              {t("profileInfo.values.none")}
            </SelectItem>
            {groups.map((g) => (
              <SelectItem key={g.id} value={g.id}>
                {g.name}
              </SelectItem>
            ))}
          </SelectContent>
        </Select>
      </div>
      {error && <p className="text-xs text-destructive-text">{error}</p>}
    </div>
  );
}

function CookiesSectionInline({
  profile,
  isRunning,
  isDisabled,
  onCopyCookies,
  onImportCookies,
  t,
}: {
  profile: BrowserProfile;
  isRunning: boolean;
  isDisabled: boolean;
  onCopyCookies?: () => void;
  onImportCookies?: () => void;
  t: (key: string, options?: Record<string, unknown>) => string;
}) {
  type CookieStats = {
    profile_id: string;
    browser_type: string;
    total_count: number;
    domains: { domain: string; count: number }[];
  };
  const [stats, setStats] = React.useState<CookieStats | null>(null);
  const [isLoading, setIsLoading] = React.useState(!isRunning);
  const [error, setError] = React.useState<string | null>(null);

  React.useEffect(() => {
    if (isRunning) {
      setStats(null);
      setIsLoading(false);
      setError(null);
      return;
    }
    let mounted = true;
    setIsLoading(true);
    setError(null);
    void (async () => {
      try {
        const data = await invoke<CookieStats>("get_profile_cookie_stats", {
          profileId: profile.id,
        });
        if (mounted) setStats(data);
      } catch (e) {
        if (mounted) setError(translateBackendError(t as never, e));
      } finally {
        if (mounted) setIsLoading(false);
      }
    })();
    return () => {
      mounted = false;
    };
  }, [profile.id, isRunning, t]);

  const [isExporting, setIsExporting] = React.useState(false);

  // Export all of this profile's cookies in one of the same formats import
  // accepts (JSON or Netscape). The backend formats every cookie; we just pick
  // a destination file.
  const handleExport = React.useCallback(
    async (format: "json" | "netscape") => {
      setIsExporting(true);
      try {
        const content = await invoke<string>("export_profile_cookies", {
          profileId: profile.id,
          format,
        });
        const ext = format === "json" ? "json" : "txt";
        const filePath = await save({
          defaultPath: `${profile.name}_cookies.${ext}`,
          filters: [
            {
              name: format === "json" ? "JSON" : "Text",
              extensions: [ext],
            },
          ],
        });
        if (!filePath) return;
        await writeTextFile(filePath, content);
        showSuccessToast(t("cookies.export.success"));
      } catch (e) {
        showErrorToast(translateBackendError(t as never, e));
      } finally {
        setIsExporting(false);
      }
    },
    [profile.id, profile.name, t],
  );

  const domains = stats?.domains ?? [];

  return (
    <div className="flex min-h-0 flex-1 flex-col gap-3">
      <div className="flex items-center justify-between gap-2">
        <div className="flex items-center gap-2 text-sm font-semibold">
          <LuCookie className="size-4" />
          {t("profileInfo.sections.cookies")}
        </div>
        <div className="flex items-center gap-2">
          <DropdownMenu>
            <DropdownMenuTrigger asChild>
              <Button
                variant="outline"
                size="sm"
                className="h-7 gap-1.5"
                disabled={
                  isDisabled ||
                  isRunning ||
                  isExporting ||
                  !stats ||
                  stats.total_count === 0
                }
              >
                <LuDownload className="size-3.5" />
                {t("common.buttons.export")}
              </Button>
            </DropdownMenuTrigger>
            <DropdownMenuContent align="end">
              <DropdownMenuItem
                onClick={() => {
                  void handleExport("json");
                }}
              >
                {t("cookies.export.json")}
              </DropdownMenuItem>
              <DropdownMenuItem
                onClick={() => {
                  void handleExport("netscape");
                }}
              >
                {t("cookies.export.netscape")}
              </DropdownMenuItem>
            </DropdownMenuContent>
          </DropdownMenu>
          {onImportCookies && (
            <Button
              variant="outline"
              size="sm"
              className="h-7 gap-1.5"
              disabled={isDisabled || isRunning}
              onClick={onImportCookies}
            >
              <LuUpload className="size-3.5" />
              {t("common.buttons.import")}
            </Button>
          )}
          {onCopyCookies && (
            <Button
              variant="outline"
              size="sm"
              className="h-7 gap-1.5"
              disabled={isDisabled}
              onClick={onCopyCookies}
            >
              <LuCopy className="size-3.5" />
              {t("common.buttons.copy")}
            </Button>
          )}
        </div>
      </div>
      <p className="text-xs text-muted-foreground">
        {t("profileInfo.sectionDesc.cookies")}
      </p>
      {isRunning ? (
        <div className="rounded-md border border-border bg-muted/40 px-3 py-2">
          <p className="text-xs text-muted-foreground">
            {t("profileInfo.cookies.runningNotice")}
          </p>
        </div>
      ) : (
        <>
          <div className="rounded-md border border-border bg-muted/40 px-3 py-2">
            <p className="text-[10px] tracking-wide text-muted-foreground uppercase">
              {t("profileInfo.fields.cookieCount")}
            </p>
            <p className="mt-0.5 text-sm">
              {isLoading
                ? t("profileInfo.values.loading")
                : stats
                  ? stats.total_count.toLocaleString()
                  : "—"}
            </p>
          </div>
          {domains.length > 0 && (
            <div className="flex min-h-0 flex-1 flex-col overflow-hidden rounded-md border border-border bg-muted/40">
              <p className="shrink-0 border-b border-border px-3 py-2 text-[10px] tracking-wide text-muted-foreground uppercase">
                {t("profileInfo.cookies.domainsHeader", {
                  count: domains.length,
                })}
              </p>
              <ul className="flex-1 space-y-1 overflow-y-auto px-3 py-2 text-xs">
                {domains.map((d) => (
                  <li
                    key={d.domain}
                    className="flex items-center justify-between gap-2"
                  >
                    <span className="truncate font-mono">{d.domain}</span>
                    <span className="text-muted-foreground tabular-nums">
                      {d.count}
                    </span>
                  </li>
                ))}
              </ul>
            </div>
          )}
          {error && <p className="text-xs text-destructive-text">{error}</p>}
        </>
      )}
    </div>
  );
}

// Inline password set / change / remove form. Replaces three separate
// nested modal dialogs with one in-page form that branches on the current
// `password_protected` state of the profile.
// Inline fingerprint editor. Reuses SharedFingerprintConfigForm so the same
// field set as the standalone dialog is available without opening a nested modal.
function FingerprintSectionInline({
  profile,
  isDisabled,
  crossOsUnlocked,
  onSaved,
  t,
}: {
  profile: BrowserProfile;
  isDisabled: boolean;
  crossOsUnlocked: boolean;
  onSaved: () => void;
  t: (key: string, options?: Record<string, unknown>) => string;
}) {
  const [wayfernConfig, setWayfernConfig] = React.useState<WayfernConfig>(
    () => profile.wayfern_config ?? {},
  );
  const [isSaving, setIsSaving] = React.useState(false);
  const [error, setError] = React.useState<string | null>(null);
  const [success, setSuccess] = React.useState<string | null>(null);

  React.useEffect(() => {
    setWayfernConfig(profile.wayfern_config ?? {});
    setError(null);
    setSuccess(null);
  }, [profile.wayfern_config]);

  const isWayfern = profile.browser === "wayfern";

  if (!isWayfern) {
    return (
      <div className="flex flex-col gap-3">
        <div className="flex items-center gap-2 text-sm font-semibold">
          <LuFingerprint className="size-4" />
          {t("profileInfo.sections.fingerprint")}
        </div>
        <p className="text-xs text-muted-foreground">
          {t("profileInfo.fingerprint.notSupported")}
        </p>
      </div>
    );
  }

  if (!crossOsUnlocked) {
    return (
      <div className="flex flex-col items-center gap-3 rounded-lg border p-6 text-center">
        <LuLock className="size-4 shrink-0 text-muted-foreground" />
        <h3 className="text-sm font-medium text-foreground">
          {t("profileInfo.fingerprint.lockedTitle")}
        </h3>
        <p className="max-w-[48ch] text-sm text-pretty text-muted-foreground">
          {t("profileInfo.fingerprint.lockedDescription")}
        </p>
      </div>
    );
  }

  const onWayfernChange = (key: keyof WayfernConfig, value: unknown) => {
    setWayfernConfig((prev) => ({ ...prev, [key]: value }));
    setSuccess(null);
  };

  const onSave = async () => {
    setIsSaving(true);
    setError(null);
    setSuccess(null);
    try {
      await invoke("update_wayfern_config", {
        profileId: profile.id,
        config: wayfernConfig,
      });
      setSuccess(t("common.buttons.saved"));
      onSaved();
    } catch (e) {
      setError(translateBackendError(t as never, e));
    } finally {
      setIsSaving(false);
    }
  };

  const initial = JSON.stringify(profile.wayfern_config ?? {});
  const current = JSON.stringify(wayfernConfig);
  const dirty = current !== initial;

  return (
    <div className="flex flex-col gap-3">
      <div className="flex items-center gap-2 text-sm font-semibold">
        <LuFingerprint className="size-4" />
        {t("profileInfo.sections.fingerprint")}
      </div>
      <p className="text-xs text-muted-foreground">
        {t("profileInfo.sectionDesc.fingerprint")}
      </p>

      <SharedFingerprintConfigForm
        config={wayfernConfig}
        onConfigChange={onWayfernChange}
        forceAdvanced={true}
        readOnly={isDisabled}
        crossOsUnlocked={crossOsUnlocked}
        limitedMode={false}
        profileVersion={profile.version}
        profileBrowser={profile.browser}
      />

      {error && <p className="text-xs text-destructive-text">{error}</p>}
      {success && !error && (
        <p className="text-xs text-success-text">{success}</p>
      )}

      <div className="mt-3 flex items-center gap-2 border-t border-border pt-3">
        <Button
          size="sm"
          className="h-7 text-xs"
          disabled={!dirty || isSaving || isDisabled}
          onClick={() => {
            void onSave();
          }}
        >
          {isSaving ? t("common.buttons.saving") : t("common.buttons.save")}
        </Button>
        {dirty && (
          <Button
            size="sm"
            variant="ghost"
            className="h-7 text-xs"
            onClick={() => {
              setWayfernConfig(profile.wayfern_config ?? {});
              setError(null);
              setSuccess(null);
            }}
          >
            {t("common.buttons.cancel")}
          </Button>
        )}
      </div>
    </div>
  );
}

function SecuritySectionInline({
  profile,
  isRunning,
  t,
}: {
  profile: BrowserProfile;
  isRunning: boolean;
  t: (key: string, options?: Record<string, unknown>) => string;
}) {
  // Mode is implied by current state: unprotected → "set"; protected →
  // "change" by default, with a "remove" alternative.
  type Mode = "set" | "change" | "remove";
  const initialMode: Mode = profile.password_protected ? "change" : "set";
  const [mode, setMode] = React.useState<Mode>(initialMode);
  const [oldPassword, setOldPassword] = React.useState("");
  const [password, setPassword] = React.useState("");
  const [confirm, setConfirm] = React.useState("");
  const [isSubmitting, setIsSubmitting] = React.useState(false);
  const [error, setError] = React.useState<string | null>(null);
  const [success, setSuccess] = React.useState<string | null>(null);
  const [isVerifyOpen, setIsVerifyOpen] = React.useState(false);
  const [verifyPassword, setVerifyPassword] = React.useState("");
  const [isVerifying, setIsVerifying] = React.useState(false);

  const onVerify = async () => {
    setIsVerifying(true);
    try {
      await invoke("verify_profile_password", {
        profileId: profile.id,
        password: verifyPassword,
      });
      showSuccessToast(t("profilePassword.verifyDialog.matchToast"));
      setIsVerifyOpen(false);
      setVerifyPassword("");
    } catch (e) {
      const message = translateBackendError(
        t as unknown as Parameters<typeof translateBackendError>[0],
        e,
      );
      showErrorToast(message);
    } finally {
      setIsVerifying(false);
    }
  };

  // Reset the form whenever the underlying profile state changes (e.g. the
  // user just set a password — flip to "change" mode and clear fields).
  React.useEffect(() => {
    setMode(profile.password_protected ? "change" : "set");
    setOldPassword("");
    setPassword("");
    setConfirm("");
    setError(null);
    setSuccess(null);
  }, [profile.password_protected]);

  const reset = () => {
    setOldPassword("");
    setPassword("");
    setConfirm("");
    setError(null);
  };

  const validate = (): string | null => {
    if (mode === "change" || mode === "remove") {
      if (!oldPassword) return t("profilePassword.errors.passwordRequired");
    }
    if (mode === "set" || mode === "change") {
      if (password.length < 8) return t("profilePassword.errors.tooShort");
      if (password !== confirm) return t("profilePassword.errors.mismatch");
    }
    return null;
  };

  const onSubmit = async () => {
    if (isRunning) return;
    const v = validate();
    if (v) {
      setError(v);
      return;
    }
    setIsSubmitting(true);
    setError(null);
    setSuccess(null);
    try {
      if (mode === "set") {
        await invoke("set_profile_password", {
          profileId: profile.id,
          password,
        });
        showSuccessToast(t("profilePassword.toasts.set"));
      } else if (mode === "change") {
        await invoke("change_profile_password", {
          profileId: profile.id,
          oldPassword,
          newPassword: password,
        });
        showSuccessToast(t("profilePassword.toasts.changed"));
      } else {
        await invoke("remove_profile_password", {
          profileId: profile.id,
          password: oldPassword,
        });
        showSuccessToast(t("profilePassword.toasts.removed"));
      }
      reset();
    } catch (e) {
      const message = translateBackendError(
        t as unknown as Parameters<typeof translateBackendError>[0],
        e,
      );
      setError(message);
      showErrorToast(message);
    } finally {
      setIsSubmitting(false);
    }
  };

  return (
    <div className="flex flex-col gap-3">
      <div className="flex items-center gap-2 text-sm font-semibold">
        <LuKey className="size-4" />
        {t("profileInfo.sections.security")}
      </div>
      <p className="text-xs text-muted-foreground">
        {profile.password_protected
          ? t("profileInfo.security.protected")
          : t("profileInfo.security.unprotected")}
      </p>

      {profile.password_protected && (
        <div className="flex gap-1.5">
          <button
            type="button"
            onClick={() => {
              setVerifyPassword("");
              setIsVerifyOpen(true);
            }}
            className={cn(
              "h-7 flex-1 rounded-md border px-2 text-xs transition-colors",
              "border-border text-muted-foreground hover:bg-accent hover:text-accent-foreground",
            )}
          >
            {t("profilePassword.modes.validate")}
          </button>
          <button
            type="button"
            onClick={() => {
              setMode("change");
              reset();
            }}
            className={cn(
              "h-7 flex-1 rounded-md border px-2 text-xs transition-colors",
              mode === "change"
                ? "border-transparent bg-accent text-accent-foreground"
                : "border-border text-muted-foreground hover:bg-accent hover:text-accent-foreground",
            )}
          >
            {t("profilePassword.modes.change")}
          </button>
          <button
            type="button"
            onClick={() => {
              setMode("remove");
              reset();
            }}
            className={cn(
              "h-7 flex-1 rounded-md border px-2 text-xs transition-colors",
              mode === "remove"
                ? "border-transparent bg-destructive/10 text-destructive-text"
                : "border-border text-muted-foreground hover:bg-accent hover:text-accent-foreground",
            )}
          >
            {t("profilePassword.modes.remove")}
          </button>
        </div>
      )}

      <div className="flex flex-col gap-2">
        {(mode === "change" || mode === "remove") && (
          <Input
            type="password"
            value={oldPassword}
            onChange={(e) => {
              setOldPassword(e.target.value);
              setError(null);
            }}
            placeholder={t("profilePassword.fields.currentPassword")}
            disabled={isRunning || isSubmitting}
            className="h-8 text-xs"
          />
        )}
        {(mode === "set" || mode === "change") && (
          <>
            <Input
              type="password"
              value={password}
              onChange={(e) => {
                setPassword(e.target.value);
                setError(null);
              }}
              placeholder={t("profilePassword.fields.newPassword")}
              disabled={isRunning || isSubmitting}
              className="h-8 text-xs"
            />
            <Input
              type="password"
              value={confirm}
              onChange={(e) => {
                setConfirm(e.target.value);
                setError(null);
              }}
              placeholder={t("profilePassword.fields.confirmPassword")}
              disabled={isRunning || isSubmitting}
              className="h-8 text-xs"
            />
          </>
        )}
      </div>

      {error && <p className="text-xs text-destructive-text">{error}</p>}
      {success && !error && (
        <p className="text-xs text-success-text">{success}</p>
      )}

      {isRunning && (
        <p className="text-xs text-muted-foreground">
          {t("profileInfo.security.cannotWhileRunning")}
        </p>
      )}

      <Button
        size="sm"
        variant={mode === "remove" ? "destructive" : "default"}
        className="h-7 self-start text-xs"
        disabled={isRunning || isSubmitting}
        onClick={() => {
          void onSubmit();
        }}
      >
        {mode === "set"
          ? t("profilePassword.modes.set")
          : mode === "change"
            ? t("profilePassword.modes.change")
            : t("profilePassword.modes.remove")}
      </Button>

      <Dialog
        open={isVerifyOpen}
        onOpenChange={(open) => {
          if (!isVerifying) {
            setIsVerifyOpen(open);
            if (!open) setVerifyPassword("");
          }
        }}
      >
        <DialogContent className="max-w-md">
          <DialogHeader>
            <DialogTitle>{t("profilePassword.verifyDialog.title")}</DialogTitle>
            <DialogDescription>
              {t("profilePassword.verifyDialog.description")}
            </DialogDescription>
          </DialogHeader>
          <Input
            type="password"
            placeholder={t("profilePassword.fields.currentPassword")}
            value={verifyPassword}
            autoFocus
            onChange={(e) => setVerifyPassword(e.target.value)}
            onKeyDown={(e) => {
              if (e.key === "Enter" && verifyPassword.length > 0) {
                e.preventDefault();
                void onVerify();
              }
            }}
          />
          <DialogFooter>
            <Button
              variant="outline"
              disabled={isVerifying}
              onClick={() => {
                setIsVerifyOpen(false);
                setVerifyPassword("");
              }}
            >
              {t("common.buttons.cancel")}
            </Button>
            <Button
              disabled={isVerifying || verifyPassword.length === 0}
              onClick={() => void onVerify()}
            >
              {isVerifying
                ? t("common.buttons.loading")
                : t("profilePassword.verifyDialog.submit")}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </div>
  );
}

interface ProfileLaunchHookDialogProps {
  isOpen: boolean;
  onClose: () => void;
  profileId: string | null;
  currentLaunchHook: string | null;
}

export function ProfileLaunchHookDialog({
  isOpen,
  onClose,
  profileId,
  currentLaunchHook,
}: ProfileLaunchHookDialogProps) {
  const { t } = useTranslation();
  const [value, setValue] = React.useState(currentLaunchHook ?? "");
  const [isSaving, setIsSaving] = React.useState(false);

  React.useEffect(() => {
    if (isOpen) {
      setValue(currentLaunchHook ?? "");
    }
  }, [isOpen, currentLaunchHook]);

  const trimmed = value.trim();
  const saved = currentLaunchHook ?? "";
  const isDirty = trimmed !== saved;

  const handleSave = async () => {
    if (!profileId) return;
    setIsSaving(true);
    try {
      await invoke("update_profile_launch_hook", {
        profileId,
        launchHook: trimmed || null,
      });
      onClose();
    } catch (err) {
      console.error("Failed to update launch hook:", err);
    } finally {
      setIsSaving(false);
    }
  };

  return (
    <Dialog open={isOpen} onOpenChange={(open) => !open && onClose()}>
      <DialogContent className="sm:max-w-md">
        <DialogHeader>
          <DialogTitle>{t("profileInfo.launchHook.title")}</DialogTitle>
        </DialogHeader>
        <p className="text-xs text-muted-foreground">
          {t("profileInfo.launchHook.description")}
        </p>
        <Input
          value={value}
          onChange={(e) => {
            setValue(e.target.value);
          }}
          placeholder={t("profileInfo.launchHook.placeholder")}
          disabled={isSaving}
        />
        <DialogFooter>
          <Button
            onClick={() => void handleSave()}
            disabled={isSaving || !isDirty}
            className="w-full"
          >
            {t("common.buttons.save")}
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}

interface ProfileDnsBlocklistDialogProps {
  isOpen: boolean;
  onClose: () => void;
  profileId: string | null;
  currentLevel: string | null;
}

export function ProfileDnsBlocklistDialog({
  isOpen,
  onClose,
  profileId,
  currentLevel,
}: ProfileDnsBlocklistDialogProps) {
  const { t } = useTranslation();
  const [level, setLevel] = React.useState(currentLevel ?? "");
  const [isSaving, setIsSaving] = React.useState(false);

  React.useEffect(() => {
    if (isOpen) {
      setLevel(currentLevel ?? "");
    }
  }, [isOpen, currentLevel]);

  const handleSave = async () => {
    if (!profileId) return;
    setIsSaving(true);
    try {
      await invoke("update_profile_dns_blocklist", {
        profileId,
        dnsBlocklist: level || null,
      });
      onClose();
    } catch (err) {
      console.error("Failed to update DNS blocklist:", err);
    } finally {
      setIsSaving(false);
    }
  };

  const options = [
    { value: "", label: t("dnsBlocklist.none") },
    ...DNS_BLOCKLIST_LEVELS.map((l) => ({
      value: l.value as string,
      label: t(l.labelKey),
    })),
  ];

  return (
    <Dialog open={isOpen} onOpenChange={(open) => !open && onClose()}>
      <DialogContent className="max-w-xs">
        <DialogHeader>
          <DialogTitle>{t("dnsBlocklist.title")}</DialogTitle>
        </DialogHeader>
        <p className="text-xs text-muted-foreground">
          {t("dnsBlocklist.settingsDescription")}{" "}
          <a
            href="https://github.com/hagezi/dns-blocklists"
            target="_blank"
            rel="noopener noreferrer"
            className="text-primary-text hover:underline"
          >
            {t("common.buttons.moreInfo")}
          </a>
        </p>
        <div className="space-y-1">
          {options.map((option) => (
            <button
              key={option.value}
              type="button"
              onClick={() => setLevel(option.value)}
              className={`w-full text-left px-3 py-2 rounded-md text-sm transition-colors ${
                level === option.value
                  ? "border border-primary/30 bg-primary/10 text-primary-text"
                  : "border border-transparent hover:bg-accent hover:text-accent-foreground"
              }`}
            >
              {option.label}
            </button>
          ))}
        </div>
        <Button
          onClick={() => void handleSave()}
          disabled={isSaving || level === (currentLevel ?? "")}
          className="w-full"
        >
          {t("common.buttons.save")}
        </Button>
      </DialogContent>
    </Dialog>
  );
}

interface ProfileBypassRulesDialogProps {
  isOpen: boolean;
  onClose: () => void;
  profileId: string | null;
  initialRules?: string[];
}

export function ProfileBypassRulesDialog({
  isOpen,
  onClose,
  profileId,
  initialRules,
}: ProfileBypassRulesDialogProps) {
  const { t } = useTranslation();
  const [bypassRules, setBypassRules] = React.useState<string[]>([]);
  const [newRule, setNewRule] = React.useState("");

  React.useEffect(() => {
    if (isOpen) {
      setBypassRules(initialRules ?? []);
      setNewRule("");
    }
  }, [isOpen, initialRules]);

  const updateBypassRules = async (rules: string[]) => {
    if (!profileId) return;
    try {
      await invoke("update_profile_proxy_bypass_rules", {
        profileId,
        rules,
      });
      setBypassRules(rules);
    } catch {
      // ignore
    }
  };

  const handleAddRule = () => {
    const trimmed = newRule.trim();
    if (!trimmed || bypassRules.includes(trimmed)) return;
    const updated = [...bypassRules, trimmed];
    setNewRule("");
    void updateBypassRules(updated);
  };

  const handleRemoveRule = (rule: string) => {
    void updateBypassRules(bypassRules.filter((r) => r !== rule));
  };

  return (
    <Dialog
      open={isOpen}
      onOpenChange={(open) => {
        if (!open) onClose();
      }}
    >
      <DialogContent className="flex max-h-[80vh] flex-col sm:max-w-lg">
        <DialogHeader className="shrink-0">
          <DialogTitle>{t("profileInfo.network.bypassRulesTitle")}</DialogTitle>
        </DialogHeader>
        <ScrollArea className="min-h-0 flex-1">
          <div className="flex flex-col gap-3 py-2">
            <p className="text-sm text-muted-foreground">
              {t("profileInfo.network.bypassRulesDescription")}
            </p>
            <div className="flex gap-2">
              <Input
                value={newRule}
                onChange={(e) => {
                  setNewRule(e.target.value);
                }}
                onKeyDown={(e) => {
                  if (e.key === "Enter") handleAddRule();
                }}
                placeholder={t("profileInfo.network.rulePlaceholder")}
                className="flex-1 text-sm"
              />
              <Button
                size="sm"
                onClick={handleAddRule}
                disabled={!newRule.trim()}
              >
                <LuPlus className="mr-1 size-4" />
                {t("profileInfo.network.addRule")}
              </Button>
            </div>
            {bypassRules.length === 0 ? (
              <p className="py-2 text-sm text-muted-foreground">
                {t("profileInfo.network.noRules")}
              </p>
            ) : (
              <div className="flex flex-col gap-1.5">
                {bypassRules.map((rule) => (
                  <div
                    key={rule}
                    className="flex items-center justify-between gap-2 rounded-md bg-muted px-3 py-1.5 text-sm"
                  >
                    <span className="truncate font-mono text-xs">{rule}</span>
                    <button
                      type="button"
                      onClick={() => {
                        handleRemoveRule(rule);
                      }}
                      className="shrink-0 text-muted-foreground transition-colors hover:text-destructive-text"
                    >
                      <LuX className="size-3.5" />
                    </button>
                  </div>
                ))}
              </div>
            )}
            <p className="text-xs text-muted-foreground">
              {t("profileInfo.network.ruleTypes")}
            </p>
          </div>
        </ScrollArea>
        <DialogFooter className="shrink-0">
          <Button variant="outline" onClick={onClose}>
            {t("common.buttons.close")}
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}
