import { useEffect, useMemo, useRef, useState, type ReactNode } from "react";
import { AdminApiClient } from "./api/client";
import type {
  AuditEvent,
  AuthResult,
  Cluster,
  ClusterAdminSummary,
  ClusterAuthorityState,
  ClusterNode,
  ClusterNodeGroup,
  CreatedJoinToken,
  FabricEntryPoint,
  FabricEntryPointNode,
  FabricEgressPool,
  FabricEgressPoolNode,
  FabricTestingFlag,
  InstallationStatus,
  JoinRequest,
  MeshLink,
  NodeHeartbeat,
  NodeSyntheticMeshConfig,
  NodeTelemetryObservation,
  NodeWorkloadDesiredState,
  OrganizationAdminSummary,
  QoSPolicy,
  RoleAssignment,
  VPNConnection,
  VPNConnectionLease,
  WorkloadStatus,
} from "./types";

const storageKeys = {
  baseUrl: "rap.webAdmin.baseUrl",
  actorUserId: "rap.webAdmin.actorUserId",
  auth: "rap.webAdmin.auth",
  language: "rap.webAdmin.language",
};

const defaultBaseUrl = "/api/v1";
const legacyDirectBackendPrefix = "http://192.168.200.61:8080/api/v1";

const roleOptions = [
  "entry-node",
  "relay-node",
  "core-mesh",
  "rdp-worker",
  "vnc-worker",
  "vpn-exit",
  "vpn-connector",
  "file-storage-cache",
  "update-cache",
  "video-relay",
];

const capabilityKeysByRole: Record<string, string[]> = {
  "entry-node": ["can_accept_client_ingress"],
  "relay-node": ["can_route_mesh", "can_accept_node_ingress"],
  "core-mesh": ["can_route_mesh", "can_accept_node_ingress"],
  "rdp-worker": ["can_run_rdp_worker"],
  "vnc-worker": ["can_run_vnc_worker"],
  "vpn-exit": ["can_run_vpn_exit"],
  "vpn-connector": ["can_run_vpn_connector"],
  "file-storage-cache": ["can_run_file_cache"],
  "update-cache": ["can_run_update_cache"],
  "video-relay": ["can_run_video_relay"],
};

const views = [
  { id: "command", ru: "Обзор", en: "Command" },
  { id: "clusters", ru: "Кластеры", en: "Clusters" },
  { id: "cluster-settings", ru: "Настройки кластера", en: "Cluster Settings" },
  { id: "nodes", ru: "Узлы", en: "Nodes" },
  { id: "enrollment", ru: "Подключение узлов", en: "Enrollment" },
  { id: "roles", ru: "Роли", en: "Roles" },
  { id: "workloads", ru: "Сервисы", en: "Workloads" },
  { id: "fabric", ru: "Связи Fabric", en: "Fabric Links" },
  { id: "vpn", ru: "VPN Control", en: "VPN Control" },
  { id: "org-safe", ru: "Организации", en: "Organizations" },
  { id: "audit", ru: "Аудит", en: "Audit" },
] as const;

type ViewId = (typeof views)[number]["id"];
type Language = "ru" | "en";
type NodeInventoryEntry = {
  node: ClusterNode;
  memberships: Array<{ cluster: Cluster; node: ClusterNode }>;
};
type NodeInventoryTreeRow =
  | { kind: "group"; key: string; label: string; depth: number; count: number; groupId?: string }
  | { kind: "node"; key: string; entry: NodeInventoryEntry; depth: number };

type WebAdminSession = {
  userId: string;
  email: string;
  authSessionId: string;
  accessToken: string;
  refreshToken: string;
  accessTokenExpiresAt: string;
  refreshTokenExpiresAt: string;
};

const copy = {
  ru: {
    productOwner: "Владелец продукта",
    controlPlane: "Панель управления",
    sideText: "Главная панель владельца платформы для кластеров, узлов, доверия, ролей и безопасного desired state.",
    signInTitle: "Вход",
    signInText: "Введите учетные данные.",
    bootstrapTitle: "Первый владелец",
    bootstrapText: "Пустая установка принимает только подписанную активацию продукта.",
    activationPayload: "Activation manifest JSON",
    activationSignature: "Подпись manifest",
    createOwner: "Создать владельца",
    creatingOwner: "Создание...",
    ownerCreated: "Владелец создан. Теперь можно войти.",
    installationLocked: "Установка уже активирована",
    insecureBootstrapDisabled: "Insecure bootstrap выключен. Нужна strict-активация с ключом продукта.",
    email: "Логин",
    password: "Пароль",
    backendApi: "Backend API",
    useLocalProxy: "Использовать локальный /api/v1 proxy",
    language: "Язык",
    deviceLabel: "Устройство",
    trustDevice: "Доверять этому устройству",
    signIn: "Войти",
    signingIn: "Вход...",
    logout: "Выйти",
    profile: "Профиль",
    refresh: "Обновить",
    refreshing: "Обновление...",
    activeCluster: "Активный кластер",
    slugLabel: "Технический код",
    slugHelp:
      "Slug — постоянный короткий технический идентификатор кластера для URL, скриптов, логов и интеграций. Его лучше не менять после создания.",
    clusterCatalog: "Каталог кластеров",
    clusterCatalogText: "Список реальных кластеров из Control Plane. Выберите активный кластер или раскройте карточку для подробностей.",
    makeActive: "Сделать активным",
    openSettings: "Открыть настройки",
    selected: "Выбран",
    createCluster: "Создать кластер",
    clusterDetails: "Подробнее",
    consoleTitle: "Панель владельца платформы",
    boundary:
      "WEB является только представлением. Решения кластера проходят через Control Plane API, PostgreSQL как source of truth и аудит.",
    noLoginError: "Войдите как владелец продукта или администратор платформы, чтобы загрузить панель.",
    accessDenied: "Доступ к этой панели запрещен.",
    emptyLiveTitle: "Кластер пока пустой",
    emptyLiveText:
      "Это реальные данные, не заглушка: в выбранном кластере ещё нет одобренных node-agent узлов. Создайте join token, запустите rap-node-agent и подтвердите join request.",
    realDataNote:
      "Показываются только данные из PostgreSQL/Control Plane. Если значения нулевые, значит соответствующих узлов, ролей или сервисов пока нет.",
    signedInAs: "Вход выполнен",
    actorUser: "Actor user",
    testMode: "Тестирование",
    testModeText: "Включает тестовую телеметрию и синтетические наблюдения связей. Это не production mesh runtime.",
    platformTestFlag: "Тестирование сервера",
    nodeTelemetry: "Телеметрия узла",
    heartbeatHistory: "История heartbeat",
    noTelemetry: "Телеметрии пока нет",
    enableTelemetry: "Включить телеметрию",
    enableSyntheticLinks: "Включить тестовые связи",
    saveTestFlag: "Сохранить флаг",
    nodeManagement: "Управление узлом",
    nodeScope: "Область просмотра",
    currentClusterNodes: "Узлы активного кластера",
    allNodes: "Все узлы платформы",
    showAllPlatformNodes: "Показать все узлы платформы",
    currentClusterMembership: "Участие в активном кластере",
    clusterMemberships: "Участие по кластерам",
    notMemberOfActiveCluster: "не состоит",
    nodeIdentity: "Физическая идентичность узла",
    activeClusterScope: "Область активного кластера",
    activeClusterScopeText:
      "Один физический узел может состоять в нескольких кластерах. Роли и desired-сервисы ниже относятся только к выбранному активному кластеру.",
    capabilityConfirmed: "способность подтверждена heartbeat",
    capabilityMissing: "способность не заявлена узлом",
    capabilityUnknown: "способность не подтверждена: нет heartbeat",
    nodeGlobalInventoryText:
      "Один физический узел показан один раз. Участие и роли остаются кластерными: в разных кластерах этот же узел может иметь разные назначения.",
    nodeSearch: "Поиск узлов",
    groupNodesBy: "Группировать",
    groupByMembership: "по участию",
    groupByHealth: "по здоровью",
    groupByOwnership: "по владению",
    groupByClusterCount: "по числу кластеров",
    nodeGroups: "Группы узлов",
    nodeGroupTree: "Дерево групп",
    nodeGroupFilter: "Фильтр по группе",
    allNodeGroups: "Все группы",
    nodeGroupCreatePanel: "Создание группы",
    nodeGroupName: "Название группы",
    parentNodeGroup: "Родительская группа",
    rootNodeGroup: "Корень",
    ungroupedNodes: "Без группы",
    createNodeGroup: "Создать группу",
    createSubgroup: "Создать подгруппу",
    collapseGroup: "Свернуть",
    expandGroup: "Развернуть",
    assignNodeGroup: "Переместить в группу",
    removeFromNodeGroup: "Убрать из группы",
    connectExistingNode: "Подключить к активному кластеру",
    connectExistingNodeTitle: "Подключить существующий узел",
    connectExistingNodeText:
      "Будет создано или повторно включено участие конкретного физического узла в активном кластере. Роли ниже назначаются только в этом кластере.",
    connectWithRoles: "Подключить с ролями",
    nodeDetails: "Сведения",
    manageNode: "Настроить",
    nodeFunctions: "Функции узла",
    nodeFunctionsText:
      "Одна строка управляет функцией целиком: роль задает разрешение в активном кластере, desired-сервис задает запуск, observed показывает факт от node-agent.",
    rolePermission: "Разрешение",
    permissionGranted: "разрешено",
    permissionDenied: "нет разрешения",
    organizationScopeForEnable: "Область организации для новых включений, опционально",
    clusterWideRolePlaceholder: "пусто = роль на весь кластер",
    desiredRuntime: "Желаемое состояние",
    observedRuntime: "Фактически",
    enableFunction: "Включить функцию",
    disableFunction: "Выключить функцию",
    close: "Закрыть",
    nodeBriefList: "Краткий список узлов",
    noActiveClusterMembership: "Узел не входит в активный кластер",
    nodeBriefListHelp:
      "Список сгруппирован деревом активного кластера. Полные сведения, управление, роли, сервисы и статистика открываются из строки узла.",
    nodeSearchPlaceholder: "имя, ключ, кластер, статус",
    nodeGroupInventoryText:
      "Группы — это кластерная инвентарная структура. Перенос узла в группу меняет только его размещение внутри активного кластера, не роли и не членство.",
    nodeGroupCreated: "Группа узлов создана.",
    noNodesTitle: "Нет узлов",
    noNodesByFilter: "По текущему фильтру узлы не найдены.",
    cancel: "Отмена",
    alreadyMember: "Уже в активном кластере",
    revokedMembership: "Участие отозвано",
    addNode: "Подключить узел",
    addNodeText:
      "Подключение существующего физического узла к активному кластеру выполняется из списка узлов: включите общий режим и нажмите «Подключить к активному кластеру».",
    joinTokenTitle: "Создать join token",
    joinTokenText:
      "Join token — временный пропуск для rap-node-agent. Он не создает узел напрямую: агент отправляет заявку, а владелец платформы подтверждает ее.",
    ttlHours: "Срок действия, часов",
    ttlHelp: "Через это время token станет недействительным, даже если им никто не воспользовался. Для ручного подключения обычно достаточно 1–24 часов.",
    maxUses: "Максимум использований",
    maxUsesHelp: "Сколько node-agent смогут использовать этот token. Самый безопасный вариант — 1 token на 1 новый узел.",
    tokenPurpose: "Назначение token",
    nodeOwnership: "Тип владения узлом",
    suggestedRoles: "Разрешенные/ожидаемые роли",
    generatedScope: "Сгенерированная область действия",
    generatedScopeHelp:
      "JSON формируется автоматически из настроек выше. Оператор не должен писать его руками, чтобы не ошибиться синтаксисом или областью доступа.",
    manualApprovalRequired: "Подтверждение заявки вручную обязательно",
    nodeRoles: "Роли узла",
    desiredServices: "Желаемые сервисы",
    observedServices: "Наблюдаемые сервисы",
    noRoles: "Ролей пока нет",
    noServices: "Сервисов пока нет",
    manageInCluster: "Управлять в кластере",
    rolesAndServices: "Роли и сервисы",
    links: "Связи",
    fabricMap: "Карта трафика Fabric",
    fabricIngressLayer: "Входы",
    fabricNodeLayer: "Узлы кластера",
    fabricEgressLayer: "Выходные зоны",
    observedPeerLinks: "Наблюдаемые связи",
    placementIntent: "control-plane назначение",
    fabricEntryPoints: "Точки входа",
    fabricEntryPointHelp: "Логические внешние входы в кластер. Они скрывают конкретные узлы от организаций и клиентов.",
    fabricEgressPools: "Выходные зоны",
    fabricEgressPoolHelp: "Логические выходы к внешним сетям, например “Офис Москва”. Организации используют зону, а не конкретный узел.",
    endpointName: "Название",
    publicEndpoint: "Публичный адрес",
    endpointType: "Тип входа",
    description: "Описание",
    routeScope: "Область маршрутов JSON",
    createEntryPoint: "Создать точку входа",
    createEgressPool: "Создать выходную зону",
    endpointNodes: "Назначенные узлы",
    assignEndpointNode: "Назначить узел",
    selectNode: "Выберите узел",
    assignedNodesEmpty: "Узлы пока не назначены",
    entryPointsEmpty: "Точки входа пока не созданы.",
    egressPoolsEmpty: "Выходные зоны пока не созданы.",
    addressNotSet: "адрес не задан",
    descriptionNotSet: "описание не задано",
    servicePlacement: "Размещение сервисов",
    trafficFlow: "Потоки между узлами",
    organizationTestFlag: "Тестирование организации",
    organizationId: "ID организации",
    saveOrganizationFlag: "Сохранить флаг организации",
    noLinks: "Связей пока нет",
    recentHeartbeats: "Последние heartbeat",
    memory: "Память",
    cpu: "Процессор",
    processes: "Процессы",
  },
  en: {
    productOwner: "Product Owner",
    controlPlane: "Control Plane",
    sideText: "Full platform-owner panel for clusters, nodes, trust, placement, and safe service desired state.",
    signInTitle: "Sign in",
    signInText: "Enter your credentials.",
    bootstrapTitle: "First owner",
    bootstrapText: "An empty installation accepts only a signed product activation.",
    activationPayload: "Activation manifest JSON",
    activationSignature: "Manifest signature",
    createOwner: "Create owner",
    creatingOwner: "Creating...",
    ownerCreated: "Owner created. You can sign in now.",
    installationLocked: "Installation is already active",
    insecureBootstrapDisabled: "Insecure bootstrap is disabled. Strict product-key activation is required.",
    email: "Login",
    password: "Password",
    backendApi: "Backend API",
    useLocalProxy: "Use local /api/v1 proxy",
    language: "Language",
    deviceLabel: "Device",
    trustDevice: "Trust this device",
    signIn: "Sign in",
    signingIn: "Signing in...",
    logout: "Logout",
    profile: "Profile",
    refresh: "Refresh",
    refreshing: "Refreshing...",
    activeCluster: "Active cluster",
    slugLabel: "Technical code",
    slugHelp:
      "Slug is a stable short technical identifier for URLs, scripts, logs, and integrations. It should generally not change after creation.",
    clusterCatalog: "Cluster catalog",
    clusterCatalogText: "Real clusters from the Control Plane. Select the active cluster or expand a card for details.",
    makeActive: "Make active",
    openSettings: "Open settings",
    selected: "Selected",
    createCluster: "Create cluster",
    clusterDetails: "Details",
    consoleTitle: "Platform Owner Console",
    boundary: "WEB is presentation only. Cluster decisions go through Control Plane APIs, PostgreSQL source of truth, and audit.",
    noLoginError: "Sign in as a product owner or platform administrator to load the panel.",
    accessDenied: "Access to this panel is denied.",
    emptyLiveTitle: "Cluster has no live nodes yet",
    emptyLiveText:
      "These are real values, not placeholders: the selected cluster has no approved node-agent nodes yet. Create a join token, run rap-node-agent, and approve the join request.",
    realDataNote: "Only PostgreSQL/Control Plane data is shown. Zero values mean the corresponding nodes, roles, or services do not exist yet.",
    signedInAs: "Signed in",
    actorUser: "Actor user",
    testMode: "Testing",
    testModeText: "Enables test telemetry and synthetic link observations. This is not production mesh runtime.",
    platformTestFlag: "Server testing",
    nodeTelemetry: "Node telemetry",
    heartbeatHistory: "Heartbeat history",
    noTelemetry: "No telemetry yet",
    enableTelemetry: "Enable telemetry",
    enableSyntheticLinks: "Enable test links",
    saveTestFlag: "Save flag",
    nodeManagement: "Node management",
    nodeScope: "View scope",
    currentClusterNodes: "Active cluster nodes",
    allNodes: "All platform nodes",
    showAllPlatformNodes: "Show all platform nodes",
    currentClusterMembership: "Active cluster membership",
    clusterMemberships: "Cluster memberships",
    notMemberOfActiveCluster: "not a member",
    nodeIdentity: "Physical node identity",
    activeClusterScope: "Active cluster scope",
    activeClusterScopeText:
      "One physical node may belong to multiple clusters. Roles and desired services below belong only to the selected active cluster.",
    capabilityConfirmed: "capability confirmed by heartbeat",
    capabilityMissing: "capability not reported by node",
    capabilityUnknown: "capability unconfirmed: no heartbeat",
    nodeGlobalInventoryText:
      "Each physical node is shown once. Membership and roles remain cluster-scoped, so the same node may have different assignments in different clusters.",
    nodeSearch: "Node search",
    groupNodesBy: "Group by",
    groupByMembership: "membership",
    groupByHealth: "health",
    groupByOwnership: "ownership",
    groupByClusterCount: "cluster count",
    nodeGroups: "Node groups",
    nodeGroupTree: "Group tree",
    nodeGroupFilter: "Group filter",
    allNodeGroups: "All groups",
    nodeGroupCreatePanel: "Create group",
    nodeGroupName: "Group name",
    parentNodeGroup: "Parent group",
    rootNodeGroup: "Root",
    ungroupedNodes: "Ungrouped",
    createNodeGroup: "Create group",
    createSubgroup: "Create subgroup",
    collapseGroup: "Collapse",
    expandGroup: "Expand",
    assignNodeGroup: "Move to group",
    removeFromNodeGroup: "Remove from group",
    connectExistingNode: "Connect to active cluster",
    connectExistingNodeTitle: "Connect existing node",
    connectExistingNodeText:
      "This creates or re-enables membership for one concrete physical node in the active cluster. Roles below are assigned only in this cluster.",
    connectWithRoles: "Connect with roles",
    nodeDetails: "Details",
    manageNode: "Configure",
    nodeFunctions: "Node functions",
    nodeFunctionsText:
      "One row controls the whole function: role grants permission in the active cluster, desired service requests runtime start, observed state reports node-agent facts.",
    rolePermission: "Permission",
    permissionGranted: "granted",
    permissionDenied: "not allowed",
    organizationScopeForEnable: "Organization scope for new enables, optional",
    clusterWideRolePlaceholder: "empty = cluster-wide role",
    desiredRuntime: "Desired state",
    observedRuntime: "Observed",
    enableFunction: "Enable function",
    disableFunction: "Disable function",
    close: "Close",
    nodeBriefList: "Compact node list",
    noActiveClusterMembership: "Node is not a member of the active cluster",
    nodeBriefListHelp:
      "The list is grouped as the active cluster tree. Full details, management, roles, services, and statistics open from the node row.",
    nodeSearchPlaceholder: "name, key, cluster, status",
    nodeGroupInventoryText:
      "Groups are a cluster inventory structure. Moving a node to a group changes only its placement inside the active cluster, not roles or membership.",
    nodeGroupCreated: "Node group created.",
    noNodesTitle: "No nodes",
    noNodesByFilter: "No nodes match the current filter.",
    cancel: "Cancel",
    alreadyMember: "Already in active cluster",
    revokedMembership: "Membership revoked",
    addNode: "Add node",
    addNodeText:
      "Connect an existing physical node to the active cluster from the node list: enable platform-wide view and click “Connect to active cluster”.",
    joinTokenTitle: "Create join token",
    joinTokenText:
      "A join token is a temporary pass for rap-node-agent. It does not create a node directly: the agent submits a request and the platform owner approves it.",
    ttlHours: "Lifetime, hours",
    ttlHelp: "After this time the token becomes invalid even if unused. For manual enrollment, 1–24 hours is usually enough.",
    maxUses: "Maximum uses",
    maxUsesHelp: "How many node-agents may use this token. The safest default is one token for one new node.",
    tokenPurpose: "Token purpose",
    nodeOwnership: "Node ownership type",
    suggestedRoles: "Allowed/expected roles",
    generatedScope: "Generated scope",
    generatedScopeHelp:
      "JSON is generated automatically from the settings above. Operators should not hand-write it and risk syntax or access-scope mistakes.",
    manualApprovalRequired: "Manual request approval is required",
    nodeRoles: "Node roles",
    desiredServices: "Desired services",
    observedServices: "Observed services",
    noRoles: "No roles yet",
    noServices: "No services yet",
    manageInCluster: "Manage in cluster",
    rolesAndServices: "Roles and services",
    links: "Links",
    fabricMap: "Fabric traffic map",
    fabricIngressLayer: "Ingress",
    fabricNodeLayer: "Cluster nodes",
    fabricEgressLayer: "Egress pools",
    observedPeerLinks: "Observed links",
    placementIntent: "control-plane placement",
    fabricEntryPoints: "Entry points",
    fabricEntryPointHelp: "Logical external ingress points for the cluster. They hide concrete nodes from organizations and clients.",
    fabricEgressPools: "Egress pools",
    fabricEgressPoolHelp: "Logical exits to external networks, for example “Office Moscow”. Organizations use the pool, not a concrete node.",
    endpointName: "Name",
    publicEndpoint: "Public endpoint",
    endpointType: "Entry type",
    description: "Description",
    routeScope: "Route scope JSON",
    createEntryPoint: "Create entry point",
    createEgressPool: "Create egress pool",
    endpointNodes: "Assigned nodes",
    assignEndpointNode: "Assign node",
    selectNode: "Select node",
    assignedNodesEmpty: "No nodes assigned yet",
    entryPointsEmpty: "No entry points created yet.",
    egressPoolsEmpty: "No egress pools created yet.",
    addressNotSet: "address not set",
    descriptionNotSet: "description not set",
    servicePlacement: "Service placement",
    trafficFlow: "Node traffic flows",
    organizationTestFlag: "Organization testing",
    organizationId: "Organization ID",
    saveOrganizationFlag: "Save organization flag",
    noLinks: "No links yet",
    recentHeartbeats: "Recent heartbeats",
    memory: "Memory",
    cpu: "CPU",
    processes: "Processes",
  },
} satisfies Record<Language, Record<string, string>>;

function normalizeAuthResult(result: AuthResult): WebAdminSession {
  const userId = result.user.id || result.user.ID || "";
  const email = result.user.email || result.user.Email || "";
  const authSessionId = result.auth_session.id || result.auth_session.ID || "";
  return {
    userId,
    email,
    authSessionId,
    accessToken: result.tokens.access_token,
    refreshToken: result.tokens.refresh_token,
    accessTokenExpiresAt: result.tokens.access_token_expires_at,
    refreshTokenExpiresAt: result.tokens.refresh_token_expires_at,
  };
}

export function App() {
  const [baseUrl] = useState(() => {
    const stored = localStorage.getItem(storageKeys.baseUrl)?.trim();
    return !stored || stored.startsWith(legacyDirectBackendPrefix) ? defaultBaseUrl : stored;
  });
  const [session, setSession] = useState<WebAdminSession | null>(null);
  const [language, setLanguage] = useState<Language>(() => (localStorage.getItem(storageKeys.language) === "en" ? "en" : "ru"));
  const [actorUserId, setActorUserId] = useState("");
  const [loginForm, setLoginForm] = useState({
    email: "",
    password: "",
    deviceLabel: "Панель владельца платформы",
    trustDevice: true,
  });
  const [installationStatus, setInstallationStatus] = useState<InstallationStatus | null>(null);
  const [bootstrapForm, setBootstrapForm] = useState({
    email: "",
    password: "",
    activationPayload: "",
    activationSignature: "",
  });
  const [activeView, setActiveView] = useState<ViewId>("command");
  const [selectedClusterId, setSelectedClusterId] = useState("");

  const [clusters, setClusters] = useState<Cluster[]>([]);
  const [clusterSummaries, setClusterSummaries] = useState<ClusterAdminSummary[]>([]);
  const [authority, setAuthority] = useState<ClusterAuthorityState | null>(null);
  const [nodes, setNodes] = useState<ClusterNode[]>([]);
  const [nodeGroups, setNodeGroups] = useState<ClusterNodeGroup[]>([]);
  const [allNodesByCluster, setAllNodesByCluster] = useState<Record<string, ClusterNode[]>>({});
  const [joinRequests, setJoinRequests] = useState<JoinRequest[]>([]);
  const [rolesByNode, setRolesByNode] = useState<Record<string, RoleAssignment[]>>({});
  const [desiredWorkloadsByNode, setDesiredWorkloadsByNode] = useState<Record<string, NodeWorkloadDesiredState[]>>({});
  const [workloadsByNode, setWorkloadsByNode] = useState<Record<string, WorkloadStatus[]>>({});
  const [heartbeatsByNode, setHeartbeatsByNode] = useState<Record<string, NodeHeartbeat[]>>({});
  const [telemetryByNode, setTelemetryByNode] = useState<Record<string, NodeTelemetryObservation[]>>({});
  const [meshLinks, setMeshLinks] = useState<MeshLink[]>([]);
  const [syntheticMeshConfigsByNode, setSyntheticMeshConfigsByNode] = useState<Record<string, NodeSyntheticMeshConfig>>({});
  const [qosPolicies, setQosPolicies] = useState<QoSPolicy[]>([]);
  const [entryPoints, setEntryPoints] = useState<FabricEntryPoint[]>([]);
  const [entryPointNodesById, setEntryPointNodesById] = useState<Record<string, FabricEntryPointNode[]>>({});
  const [egressPools, setEgressPools] = useState<FabricEgressPool[]>([]);
  const [egressPoolNodesById, setEgressPoolNodesById] = useState<Record<string, FabricEgressPoolNode[]>>({});
  const [testingFlags, setTestingFlags] = useState<FabricTestingFlag[]>([]);
  const [vpnConnections, setVPNConnections] = useState<VPNConnection[]>([]);
  const [vpnLeases, setVPNLeases] = useState<Record<string, VPNConnectionLease | null>>({});
  const [audit, setAudit] = useState<AuditEvent[]>([]);

  const [organizationId, setOrganizationId] = useState("");
  const [organizationSummary, setOrganizationSummary] = useState<OrganizationAdminSummary | null>(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState("");
  const [notice, setNotice] = useState("");

  const [clusterForm, setClusterForm] = useState({ slug: "", name: "", region: "" });
  const [clusterSettingsForm, setClusterSettingsForm] = useState({ name: "", status: "active", region: "", metadataJson: "{}" });
  const [nodeGroupForm, setNodeGroupForm] = useState({ name: "", parentGroupId: "" });
  const [entryPointForm, setEntryPointForm] = useState({ name: "", endpointType: "client_access", publicEndpoint: "" });
  const [egressPoolForm, setEgressPoolForm] = useState({ name: "", description: "", routeScope: "{\n  \"routes\": []\n}" });
  const [joinTokenForm, setJoinTokenForm] = useState({
    ttlHours: 24,
    maxUses: 1,
    roles: ["entry-node"],
    ownershipType: "platform_managed",
    purpose: "",
  });
  const [lastJoinToken, setLastJoinToken] = useState<CreatedJoinToken | null>(null);
  const [authorityForm, setAuthorityForm] = useState({ authorityState: "authoritative", mutationMode: "normal", notes: "" });
  const [roleOrgScope, setRoleOrgScope] = useState("");
  const [nodeViewScope, setNodeViewScope] = useState<"cluster" | "all">("cluster");
  const [allNodeSearch, setAllNodeSearch] = useState("");
  const [nodeGroupFilterId, setNodeGroupFilterId] = useState("");
  const [collapsedNodeGroupKeys, setCollapsedNodeGroupKeys] = useState<string[]>([]);
  const [allNodeGroupBy, setAllNodeGroupBy] = useState<"membership" | "health" | "ownership" | "cluster_count">("membership");
  const [attachNodeDialog, setAttachNodeDialog] = useState<{ node: ClusterNode; memberships: Array<{ cluster: Cluster; node: ClusterNode }> } | null>(null);
  const [attachNodeRoles, setAttachNodeRoles] = useState<string[]>([]);
  const [nodeInfoDialog, setNodeInfoDialog] = useState<NodeInventoryEntry | null>(null);
  const [nodeInfoMode, setNodeInfoMode] = useState<"details" | "manage">("details");
  const [nodeRoleDrafts, setNodeRoleDrafts] = useState<Record<string, string>>({});
  const [nodeWorkloadDrafts, setNodeWorkloadDrafts] = useState<Record<string, string>>({});
  const [entryPointNodeDrafts, setEntryPointNodeDrafts] = useState<Record<string, string>>({});
  const [egressPoolNodeDrafts, setEgressPoolNodeDrafts] = useState<Record<string, string>>({});
  const [nodeTestingDrafts, setNodeTestingDrafts] = useState<Record<string, { telemetry: boolean; links: boolean }>>({});
  const [testingOrgId, setTestingOrgId] = useState("");
  const [testingOrgDraft, setTestingOrgDraft] = useState({ telemetry: true, links: true });
  const [workloadForm, setWorkloadForm] = useState({
    nodeId: "",
    serviceType: "entry-node",
    desiredState: "enabled",
    runtimeMode: "container",
    version: "",
    configJson: "{}",
    environmentJson: "{}",
  });
  const [vpnForm, setVPNForm] = useState({
    organizationId: "",
    name: "",
    protocolFamily: "generic",
    desiredState: "disabled",
    credentialRef: "",
    targetEndpointJson: "{}",
    allowedNodePolicyJson: `{"mode":"explicit","node_ids":[]}`,
    routingUsageJson: "[]",
    routePolicyJson: "{}",
    qosPolicyJson: "{}",
    placementPolicyJson: "{}",
  });

  const client = useMemo(() => new AdminApiClient({ baseUrl, actorUserId }), [baseUrl, actorUserId]);
  const authClient = useMemo(() => new AdminApiClient({ baseUrl, actorUserId: "" }), [baseUrl]);
  const clusterScopeRequestSeq = useRef(0);
  const t = copy[language];
  const selectedCluster = clusters.find((cluster) => cluster.id === selectedClusterId) || null;
  const selectedSummary = clusterSummaries.find((summary) => summary.cluster_id === selectedClusterId) || null;
  const joinTokenScope = useMemo(() => buildJoinTokenScope(joinTokenForm), [joinTokenForm]);
  const allNodeInventory = useMemo(() => {
    const grouped = new Map<
      string,
      {
        node: ClusterNode;
        memberships: Array<{ cluster: Cluster; node: ClusterNode }>;
      }
    >();

    for (const cluster of clusters) {
      for (const node of allNodesByCluster[cluster.id] || []) {
        const current = grouped.get(node.id);
        if (current) {
          current.memberships.push({ cluster, node });
          if ((node.last_seen_at || "") > (current.node.last_seen_at || "")) {
            current.node = node;
          }
        } else {
          grouped.set(node.id, { node, memberships: [{ cluster, node }] });
        }
      }
    }

    return Array.from(grouped.values()).sort((left, right) => left.node.name.localeCompare(right.node.name));
  }, [allNodesByCluster, clusters]);
  const groupedAllNodeInventory = useMemo(
    () => groupNodeInventory(allNodeInventory, selectedClusterId, allNodeSearch, allNodeGroupBy, language),
    [allNodeInventory, allNodeGroupBy, allNodeSearch, language, selectedClusterId],
  );
  const visibleNodeInventory = useMemo(() => {
    const normalizedSearch = allNodeSearch.trim().toLowerCase();
    const allowedGroupIds = nodeGroupFilterId ? new Set([nodeGroupFilterId, ...descendantGroupIds(nodeGroupFilterId, nodeGroups)]) : null;
    return allNodeInventory.filter((entry) => {
      const hasActiveClusterMembership = entry.memberships.some((membership) => membership.cluster.id === selectedClusterId);
      if (nodeViewScope !== "all" && !hasActiveClusterMembership) {
        return false;
      }
      if (allowedGroupIds) {
        const activeMembership = entry.memberships.find((membership) => membership.cluster.id === selectedClusterId);
        if (!activeMembership?.node.node_group_id || !allowedGroupIds.has(activeMembership.node.node_group_id)) {
          return false;
        }
      }
      return !normalizedSearch || nodeInventoryMatches(entry, normalizedSearch);
    });
  }, [allNodeInventory, allNodeSearch, nodeGroupFilterId, nodeGroups, nodeViewScope, selectedClusterId]);
  const visibleNodeTreeRows = useMemo(
    () => buildNodeInventoryTreeRows(visibleNodeInventory, nodeGroups, selectedClusterId, t, new Set(collapsedNodeGroupKeys)),
    [collapsedNodeGroupKeys, nodeGroups, selectedClusterId, t, visibleNodeInventory],
  );

  useEffect(() => {
    let cancelled = false;
    authClient
      .getInstallationStatus()
      .then((status) => {
        if (!cancelled) {
          setInstallationStatus(status);
        }
      })
      .catch((err) => {
        if (!cancelled) {
          setError(err instanceof Error ? err.message : "Не удалось загрузить статус установки.");
        }
      });
    return () => {
      cancelled = true;
    };
  }, [authClient]);

  useEffect(() => {
    if (!selectedCluster) {
      setClusterSettingsForm({ name: "", status: "active", region: "", metadataJson: "{}" });
      return;
    }
    setClusterSettingsForm({
      name: selectedCluster.name,
      status: selectedCluster.status || "active",
      region: selectedCluster.region || "",
      metadataJson: JSON.stringify(selectedCluster.metadata || {}, null, 2),
    });
  }, [selectedCluster]);

  useEffect(() => {
    setNodeGroupFilterId("");
    setNodeGroupForm({ name: "", parentGroupId: "" });
    setCollapsedNodeGroupKeys([]);
  }, [selectedClusterId]);

  useEffect(() => {
    setAttachNodeDialog(null);
    setAttachNodeRoles([]);
  }, [selectedClusterId]);

  useEffect(() => {
    localStorage.setItem(storageKeys.baseUrl, baseUrl);
    localStorage.setItem(storageKeys.language, language);
    if (session) {
      localStorage.setItem(`${storageKeys.language}.${session.userId}`, language);
    } else {
      localStorage.removeItem(storageKeys.auth);
      localStorage.removeItem(storageKeys.actorUserId);
    }
  }, [baseUrl, actorUserId, language, session]);

  useEffect(() => {
    if (!session) {
      return;
    }
    const userLanguage = localStorage.getItem(`${storageKeys.language}.${session.userId}`);
    if (userLanguage === "ru" || userLanguage === "en") {
      setLanguage(userLanguage);
    }
  }, [session?.userId]);

  useEffect(() => {
    if (session) {
      void refreshAll();
    }
    // First load only. The operator keeps refresh timing explicit after that.
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [session?.userId]);

  async function refreshAll(preferredClusterId = selectedClusterId) {
    if (!actorUserId.trim()) {
      setError(t.noLoginError);
      return;
    }
    setLoading(true);
    setError("");
    setNotice("");
    try {
      const [loadedClusters, loadedSummaries] = await Promise.all([client.listClusters(), client.listClusterSummaries()]);
      setClusters(loadedClusters);
      setClusterSummaries(loadedSummaries);
      const allNodeEntries = await Promise.all(loadedClusters.map(async (cluster) => [cluster.id, await client.listNodes(cluster.id)] as const));
      setAllNodesByCluster(Object.fromEntries(allNodeEntries));
      const clusterId = preferredClusterId || loadedClusters[0]?.id || "";
      setSelectedClusterId(clusterId);
      if (clusterId) {
        await loadClusterScope(clusterId);
      }
    } catch (err) {
      setError(err instanceof Error ? err.message : "Неизвестная ошибка панели управления платформой.");
    } finally {
      setLoading(false);
    }
  }

  async function loadClusterScope(clusterId: string) {
    const requestSeq = ++clusterScopeRequestSeq.current;
    const [
      loadedNodes,
      loadedNodeGroups,
      loadedJoinRequests,
      loadedAuthority,
      loadedAudit,
      loadedMeshLinks,
      loadedQosPolicies,
      loadedEntryPoints,
      loadedEgressPools,
      loadedVPNConnections,
      loadedTestingFlags,
    ] =
      await Promise.all([
        client.listNodes(clusterId),
        client.listNodeGroups(clusterId),
        client.listJoinRequests(clusterId),
        client.getClusterAuthority(clusterId),
        client.listAudit(clusterId),
        client.listMeshLinks(clusterId),
        client.listQoSPolicies(clusterId),
        client.listFabricEntryPoints(clusterId),
        client.listFabricEgressPools(clusterId),
        client.listVPNConnections(clusterId),
        client.listFabricTestingFlags(),
      ]);
    if (requestSeq !== clusterScopeRequestSeq.current) {
      return;
    }
    setNodes(loadedNodes);
    setNodeGroups(loadedNodeGroups);
    setJoinRequests(loadedJoinRequests);
    setAuthority(loadedAuthority);
    setAuthorityForm({
      authorityState: loadedAuthority.authority_state,
      mutationMode: loadedAuthority.mutation_mode,
      notes: loadedAuthority.notes || "",
    });
    setAudit(loadedAudit);
    setMeshLinks(loadedMeshLinks);
    setQosPolicies(loadedQosPolicies);
    setEntryPoints(loadedEntryPoints);
    setEgressPools(loadedEgressPools);
    setVPNConnections(loadedVPNConnections);
    setTestingFlags(loadedTestingFlags);

    const [entryPointNodeEntries, egressPoolNodeEntries] = await Promise.all([
      Promise.all(loadedEntryPoints.map(async (entryPoint) => [entryPoint.id, await client.listFabricEntryPointNodes(clusterId, entryPoint.id)] as const)),
      Promise.all(loadedEgressPools.map(async (pool) => [pool.id, await client.listFabricEgressPoolNodes(clusterId, pool.id)] as const)),
    ]);
    if (requestSeq !== clusterScopeRequestSeq.current) {
      return;
    }
    setEntryPointNodesById(Object.fromEntries(entryPointNodeEntries));
    setEgressPoolNodesById(Object.fromEntries(egressPoolNodeEntries));

    const roleEntries = await Promise.all(loadedNodes.map(async (node) => [node.id, await client.listNodeRoles(clusterId, node.id)] as const));
    if (requestSeq !== clusterScopeRequestSeq.current) {
      return;
    }
    setRolesByNode(Object.fromEntries(roleEntries));

    const desiredEntries = await Promise.all(loadedNodes.map(async (node) => [node.id, await client.listDesiredWorkloads(clusterId, node.id)] as const));
    if (requestSeq !== clusterScopeRequestSeq.current) {
      return;
    }
    setDesiredWorkloadsByNode(Object.fromEntries(desiredEntries));

    const workloadEntries = await Promise.all(
      loadedNodes.map(async (node) => [node.id, await client.listWorkloadStatuses(clusterId, node.id)] as const),
    );
    if (requestSeq !== clusterScopeRequestSeq.current) {
      return;
    }
    setWorkloadsByNode(Object.fromEntries(workloadEntries));

    const heartbeatEntries = await Promise.all(
      loadedNodes.map(async (node) => [node.id, await client.listNodeHeartbeats(clusterId, node.id, 60)] as const),
    );
    if (requestSeq !== clusterScopeRequestSeq.current) {
      return;
    }
    setHeartbeatsByNode(Object.fromEntries(heartbeatEntries));

    const telemetryEntries = await Promise.all(
      loadedNodes.map(async (node) => [node.id, await client.listNodeTelemetry(clusterId, node.id, 120)] as const),
    );
    if (requestSeq !== clusterScopeRequestSeq.current) {
      return;
    }
    setTelemetryByNode(Object.fromEntries(telemetryEntries));

    const syntheticMeshConfigEntries = await Promise.all(
      loadedNodes.map(async (node) => [node.id, await client.getNodeSyntheticMeshConfig(clusterId, node.id)] as const),
    );
    if (requestSeq !== clusterScopeRequestSeq.current) {
      return;
    }
    setSyntheticMeshConfigsByNode(Object.fromEntries(syntheticMeshConfigEntries));

    const leaseEntries = await Promise.all(
      loadedVPNConnections.map(async (connection) => [connection.id, await client.getActiveVPNLease(clusterId, connection.id)] as const),
    );
    if (requestSeq !== clusterScopeRequestSeq.current) {
      return;
    }
    setVPNLeases(Object.fromEntries(leaseEntries));
  }

  function clearClusterScope() {
    setNodes([]);
    setNodeGroups([]);
    setJoinRequests([]);
    setAuthority(null);
    setRolesByNode({});
    setDesiredWorkloadsByNode({});
    setWorkloadsByNode({});
    setHeartbeatsByNode({});
    setTelemetryByNode({});
    setMeshLinks([]);
    setSyntheticMeshConfigsByNode({});
    setQosPolicies([]);
    setEntryPoints([]);
    setEntryPointNodesById({});
    setEgressPools([]);
    setEgressPoolNodesById({});
    setTestingFlags([]);
    setVPNConnections([]);
    setVPNLeases({});
    setAudit([]);
  }

  async function runAction(action: () => Promise<unknown>, success: string) {
    setLoading(true);
    setError("");
    setNotice("");
    try {
      await action();
      setNotice(success);
      await refreshAll();
    } catch (err) {
      setError(err instanceof Error ? err.message : "Действие не выполнено.");
    } finally {
      setLoading(false);
    }
  }

  async function handleLogin() {
    setLoading(true);
    setError("");
    setNotice("");
    try {
      const result = await authClient.login({
        email: loginForm.email,
        password: loginForm.password,
        deviceLabel: loginForm.deviceLabel,
        trustDevice: loginForm.trustDevice,
      });
      const nextSession = normalizeAuthResult(result);
      if (!nextSession.userId || !nextSession.authSessionId) {
        throw new Error("Ответ входа не содержит пользователя или сессию.");
      }
      const accessClient = new AdminApiClient({ baseUrl, actorUserId: nextSession.userId });
      try {
        await accessClient.listClusterSummaries();
      } catch {
        try {
          await authClient.revokeAuthSession({
            userId: nextSession.userId,
            authSessionId: nextSession.authSessionId,
            reason: "platform_owner_console_access_denied",
          });
        } catch {
          // Authentication succeeded, but this panel is not authorized for the user.
        }
        throw new Error(t.accessDenied);
      }
      setSession(nextSession);
      setActorUserId(nextSession.userId);
      setNotice(`${t.signedInAs}: ${nextSession.email}`);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Вход не выполнен.");
    } finally {
      setLoading(false);
    }
  }

  async function handleBootstrapOwner() {
    setLoading(true);
    setError("");
    setNotice("");
    try {
      let activationPayload: unknown;
      if (installationStatus?.strict_authority) {
        if (!bootstrapForm.activationPayload.trim() || !bootstrapForm.activationSignature.trim()) {
          throw new Error(t.bootstrapText);
        }
        activationPayload = JSON.parse(bootstrapForm.activationPayload);
      }
      const result = await authClient.bootstrapOwner({
        email: bootstrapForm.email,
        password: bootstrapForm.password,
        activationPayload,
        activationSignature: bootstrapForm.activationSignature,
      });
      setInstallationStatus(result.installation);
      setLoginForm({ ...loginForm, email: bootstrapForm.email, password: bootstrapForm.password });
      setNotice(t.ownerCreated);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Создание владельца не выполнено.");
    } finally {
      setLoading(false);
    }
  }

  async function handleLogout() {
    const previous = session;
    setSession(null);
    setActorUserId("");
    setClusters([]);
    setClusterSummaries([]);
    clearClusterScope();
    setAllNodesByCluster({});
    setSelectedClusterId("");
    if (previous?.userId && previous.authSessionId) {
      try {
        await authClient.revokeAuthSession({
          userId: previous.userId,
          authSessionId: previous.authSessionId,
          reason: "platform_owner_console_logout",
        });
      } catch {
        // The local session is already cleared. Backend revoke failure should not trap the operator in the UI.
      }
    }
  }

  async function switchCluster(clusterId: string) {
    setSelectedClusterId(clusterId);
    clearClusterScope();
    setLoading(true);
    setError("");
    setNotice("");
    try {
      await loadClusterScope(clusterId);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Не удалось загрузить кластер.");
    } finally {
      setLoading(false);
    }
  }

  const pendingJoinCount = joinRequests.filter((request) => request.status === "pending").length;
  const healthyNodeCount = nodes.filter((node) => node.health_status === "healthy").length;
  const riskyNodeCount = nodes.filter((node) => node.health_status === "critical" || node.membership_status !== "active").length;
  const activeRoleCount = Object.values(rolesByNode).flat().filter((role) => role.status === "active").length;
  const platformTestingFlag = testingFlags.find((flag) => flag.scope_type === "platform" && !flag.scope_id) || null;
  const organizationTestingFlag =
    testingFlags.find((flag) => flag.scope_type === "organization" && flag.scope_id === testingOrgId && (!flag.cluster_id || flag.cluster_id === selectedClusterId)) ||
    null;
  const syntheticMeshConfigs = Object.values(syntheticMeshConfigsByNode);
  const syntheticConfigEnabledCount = syntheticMeshConfigs.filter((config) => config.enabled).length;
  const syntheticRouteCount = syntheticMeshConfigs.reduce((sum, config) => sum + config.routes.length, 0);
  const syntheticPeerEndpointCount = syntheticMeshConfigs.reduce((sum, config) => sum + Object.keys(config.peer_endpoints || {}).length, 0);
  const syntheticCandidateCount = syntheticMeshConfigs.reduce((sum, config) => sum + countPeerEndpointCandidates(config), 0);
  const syntheticPeerDirectoryCount = syntheticMeshConfigs.reduce((sum, config) => sum + (config.peer_directory?.length ?? 0), 0);
  const syntheticRecoverySeedCount = syntheticMeshConfigs.reduce((sum, config) => sum + (config.recovery_seeds?.length ?? 0), 0);
  const productionForwardingConfigCount = syntheticMeshConfigs.filter((config) => config.production_forwarding).length;
  const bootstrapRequired = installationStatus?.bootstrapped === false;
  const bootstrapBlocked = bootstrapRequired && !installationStatus?.strict_authority && !installationStatus?.insecure_bootstrap_allowed;

  if (!session) {
    return (
      <main className="loginShell">
        {installationStatus && (
          <section className="loginCard">
            <h1>{installationStatus.bootstrapped ? t.installationLocked : t.bootstrapTitle}</h1>
            <StateLine label="Authority" value={`${installationStatus.authority_mode}/${installationStatus.authority_state}`} />
            <StateLine label="Strict" value={installationStatus.strict_authority ? "enabled" : "legacy"} />
            {installationStatus.root_fingerprint && <StateLine label="Root key" value={shortId(installationStatus.root_fingerprint)} />}
          </section>
        )}

        {bootstrapRequired ? (
          <section className="loginCard">
            <h1>{t.bootstrapTitle}</h1>
            <p className="loginHint">{bootstrapBlocked ? t.insecureBootstrapDisabled : t.bootstrapText}</p>
            <label>
              {t.email}
              <input
                value={bootstrapForm.email}
                onChange={(event) => setBootstrapForm({ ...bootstrapForm, email: event.target.value })}
                autoComplete="username"
              />
            </label>
            <label>
              {t.password}
              <input
                value={bootstrapForm.password}
                onChange={(event) => setBootstrapForm({ ...bootstrapForm, password: event.target.value })}
                type="password"
                autoComplete="new-password"
              />
            </label>
            {installationStatus?.strict_authority && (
              <>
                <label>
                  {t.activationPayload}
                  <textarea
                    value={bootstrapForm.activationPayload}
                    onChange={(event) => setBootstrapForm({ ...bootstrapForm, activationPayload: event.target.value })}
                    spellCheck={false}
                  />
                </label>
                <label>
                  {t.activationSignature}
                  <input
                    value={bootstrapForm.activationSignature}
                    onChange={(event) => setBootstrapForm({ ...bootstrapForm, activationSignature: event.target.value })}
                    spellCheck={false}
                  />
                </label>
              </>
            )}

            {error && <div className="errorPanel">{error}</div>}
            {notice && <div className="noticePanel">{notice}</div>}

            <button
              className="primary wide"
              onClick={() => void handleBootstrapOwner()}
              disabled={
                loading ||
                bootstrapBlocked ||
                !bootstrapForm.email ||
                bootstrapForm.password.length < 12 ||
                (installationStatus?.strict_authority && (!bootstrapForm.activationPayload || !bootstrapForm.activationSignature))
              }
            >
              {loading ? t.creatingOwner : t.createOwner}
            </button>
          </section>
        ) : (
          <section className="loginCard">
            <h1>{t.signInTitle}</h1>
            <label>
              {t.email}
              <input
                value={loginForm.email}
                onChange={(event) => setLoginForm({ ...loginForm, email: event.target.value })}
                autoComplete="username"
              />
            </label>
            <label>
              {t.password}
              <input
                value={loginForm.password}
                onChange={(event) => setLoginForm({ ...loginForm, password: event.target.value })}
                type="password"
                autoComplete="current-password"
                onKeyDown={(event) => {
                  if (event.key === "Enter") {
                    void handleLogin();
                  }
                }}
              />
            </label>

            {error && <div className="errorPanel">{error}</div>}
            {notice && <div className="noticePanel">{notice}</div>}

            <button className="primary wide" onClick={() => void handleLogin()} disabled={loading || !loginForm.email || !loginForm.password}>
              {loading ? t.signingIn : t.signIn}
            </button>
          </section>
        )}
      </main>
    );
  }

  return (
    <main className="consoleShell">
      <aside className="sideRail">
        <div className="brandMark">SAF</div>
        <p className="sideKicker">{t.productOwner}</p>
        <h1>{t.controlPlane}</h1>
        <p className="sideText">{t.sideText}</p>
        <nav className="railNav">
          {views.filter((view) => view.id !== "enrollment" && view.id !== "roles").map((view) => (
            <button key={view.id} className={activeView === view.id ? "active" : ""} onClick={() => setActiveView(view.id)}>
              {view[language]}
            </button>
          ))}
        </nav>
      </aside>

      <section className="workspace">
        <header className="topBar">
          <div>
            <p className="eyebrow">Secure Access Fabric</p>
            <h2>{selectedCluster ? selectedCluster.name : t.consoleTitle}</h2>
            <p className="muted">{t.boundary}</p>
          </div>
          <div className="clusterPicker">
            <label>
              {t.activeCluster}
              <select value={selectedClusterId} onChange={(event) => void switchCluster(event.target.value)}>
                {clusters.map((cluster) => (
                  <option key={cluster.id} value={cluster.id}>
                    {cluster.name}
                  </option>
                ))}
              </select>
            </label>
            <span>
              {t.slugLabel}: {selectedCluster?.slug || "н/д"}
            </span>
          </div>
          <button className="primary" onClick={() => void refreshAll()} disabled={loading}>
            {loading ? t.refreshing : t.refresh}
          </button>
          <div className="profilePanel">
            <strong>{t.profile}</strong>
            <span>{session.email}</span>
            <label>
              {t.language}
              <select value={language} onChange={(event) => setLanguage(event.target.value as Language)}>
                <option value="ru">Русский</option>
                <option value="en">{language === "ru" ? "Английский" : "English"}</option>
              </select>
            </label>
            <button className="ghost" onClick={() => void handleLogout()} disabled={loading}>
              {t.logout}
            </button>
          </div>
        </header>

        {error && <div className="errorPanel">{error}</div>}
        {notice && <div className="noticePanel">{notice}</div>}
        {selectedCluster && nodes.length === 0 && (
          <div className="noticePanel">
            <strong>{t.emptyLiveTitle}.</strong> {t.emptyLiveText}
          </div>
        )}

        {activeView === "command" && (
          <section className="grid five">
            <Metric label="Кластеры" value={clusters.length} tone="steel" />
            <Metric label="Узлы в области" value={nodes.length} tone="green" />
            <Metric label="Здоровые узлы" value={healthyNodeCount} tone="green" />
            <Metric label="Ожидают подключения" value={pendingJoinCount} tone="amber" />
            <Metric label="Рискованные состояния" value={riskyNodeCount} tone="red" />

            <article className="card span3">
              <h3>Общее состояние кластеров</h3>
              <DataTable
                columns={["кластер", "authority", "ключ", "режим изменений", "узлы", "заявки", "роли", "последний сигнал"]}
                rows={clusterSummaries.map((summary) => [
                  summary.name,
                  summary.authority_state,
                  shortId(summary.cluster_key_fingerprint),
                  summary.mutation_mode,
                  `${summary.healthy_node_count}/${summary.node_count}`,
                  String(summary.pending_join_count),
                  String(summary.active_role_assignment_count),
                  formatDate(summary.last_node_seen_at),
                ])}
              />
            </article>

            <article className="card span2">
              <h3>Authority выбранного кластера</h3>
              {authority ? (
                <div className="stateList">
                  <StateLine label="Authority" value={authority.authority_state} />
                  <StateLine label="Режим изменений" value={authority.mutation_mode} />
                  <StateLine label="Терм" value={String(authority.term)} />
                  <StateLine label="Cluster key" value={shortId(selectedSummary?.cluster_key_fingerprint)} />
                  <StateLine label="Обновлено" value={formatDate(authority.updated_at)} />
                </div>
              ) : (
                <EmptyState title="Нет состояния authority" text="Выберите кластер, чтобы загрузить состояние authority." />
              )}
            </article>

            <article className="card span2">
              <h3>Граница платформы</h3>
              <p className="muted">
                Эта панель предназначена для владельца продукта / владельца платформы. Панели организаций должны использовать безопасные
                проекции и не раскрывать mesh internals, peer cache, route cache, секреты или данные других tenants.
              </p>
            </article>

            <article className="card span3">
              <h3>Текущие сигналы кластера</h3>
              <div className="signalStrip">
                <Signal label="Активные роли" value={String(activeRoleCount)} />
                <Signal label="Отчеты сервисов" value={String(Object.values(workloadsByNode).filter((items) => items.length > 0).length)} />
                <Signal label="Наблюдения связей" value={String(meshLinks.length)} />
                <Signal label="Synthetic configs" value={`${syntheticConfigEnabledCount}/${nodes.length}`} />
              </div>
            </article>
          </section>
        )}

        {activeView === "clusters" && (
          <section className="grid two">
            <article className="card span2">
              <div className="cardHead">
                <div>
                  <h3>{t.clusterCatalog}</h3>
                  <p className="muted">{t.clusterCatalogText}</p>
                </div>
                <span className="pill">{clusterCountLabel(clusters.length, language)}</span>
              </div>
              <div className="clusterCatalog">
                {clusters.map((cluster) => {
                  const summary = clusterSummaries.find((item) => item.cluster_id === cluster.id);
                  const isSelected = cluster.id === selectedClusterId;
                  return (
                    <article key={cluster.id} className={`clusterCard ${isSelected ? "selected" : ""}`}>
                      <div className="clusterCardMain">
                        <div>
                          <p className="eyebrow">{cluster.region || "регион не задан"}</p>
                          <h4>{cluster.name}</h4>
                          <p className="muted">
                            {t.slugLabel}: <strong>{cluster.slug}</strong>
                          </p>
                        </div>
                        <div className="clusterCardActions">
                          <Status value={cluster.status} />
                          {isSelected ? (
                            <span className="pill good">{t.selected}</span>
                          ) : (
                            <button onClick={() => void switchCluster(cluster.id)}>{t.makeActive}</button>
                          )}
                          <button
                            className="ghost"
                            onClick={() => {
                              void switchCluster(cluster.id);
                              setActiveView("cluster-settings");
                            }}
                          >
                            {t.openSettings}
                          </button>
                        </div>
                      </div>

                      <div className="signalStrip compact">
                        <Signal label="Узлы" value={summary ? `${summary.healthy_node_count}/${summary.node_count}` : "н/д"} />
                        <Signal label="Заявки" value={String(summary?.pending_join_count ?? "н/д")} />
                        <Signal label="Роли" value={String(summary?.active_role_assignment_count ?? "н/д")} />
                        <Signal label="Последний сигнал" value={formatDate(summary?.last_node_seen_at)} />
                      </div>

                      <details>
                        <summary>{t.clusterDetails}</summary>
                        <div className="stateList">
                          <StateLine label="ID" value={cluster.id} />
                          <StateLine label={t.slugLabel} value={cluster.slug} />
                          <StateLine label="Статус" value={statusLabel(cluster.status)} />
                          <StateLine label="Authority" value={summary ? `${summary.authority_state}/${summary.mutation_mode}` : "неизвестно"} />
                          <StateLine label="Создан" value={formatDate(cluster.created_at)} />
                          <StateLine label="Обновлен" value={formatDate(cluster.updated_at || cluster.created_at)} />
                        </div>
                      </details>
                    </article>
                  );
                })}
                {clusters.length === 0 && <EmptyState title="Кластеров нет" text="Создайте первый кластер, затем подключите стартовый node-agent." />}
              </div>
            </article>

            <article className="card">
              <h3>{t.createCluster}</h3>
              <FormGrid>
                <label>
                  {t.slugLabel}
                  <input value={clusterForm.slug} onChange={(event) => setClusterForm({ ...clusterForm, slug: event.target.value })} />
                </label>
                <label>
                  Название
                  <input value={clusterForm.name} onChange={(event) => setClusterForm({ ...clusterForm, name: event.target.value })} />
                </label>
                <label>
                  Регион
                  <input value={clusterForm.region} onChange={(event) => setClusterForm({ ...clusterForm, region: event.target.value })} />
                </label>
              </FormGrid>
              <p className="muted">{t.slugHelp}</p>
              <button
                className="primary"
                disabled={!clusterForm.slug || !clusterForm.name}
                onClick={() =>
                  void runAction(async () => {
                    await client.createCluster({ slug: clusterForm.slug, name: clusterForm.name, region: clusterForm.region || null });
                    setClusterForm({ slug: "", name: "", region: "" });
                  }, "Кластер создан.")
                }
              >
                {t.createCluster}
              </button>
            </article>

            <article className="card">
              <h3>Что такое технический код?</h3>
              <p className="muted">{t.slugHelp}</p>
              <p className="muted">
                Для человека основное поле — название. Для системы и операторов — технический код. Он нужен, чтобы сценарии, логи и будущие
                endpoint-адреса не зависели от переименования кластера.
              </p>
            </article>
          </section>
        )}

        {activeView === "cluster-settings" && (
          <section className="grid two">
            {!selectedCluster && <EmptyState title="Кластер не выбран" text="Выберите активный кластер, чтобы открыть настройки." />}

            {selectedCluster && (
              <>
                <article className="card">
                  <h3>Identity кластера</h3>
                  <p className="muted">Базовые параметры хранятся в PostgreSQL. Slug остается неизменяемым идентификатором для операторов и скриптов.</p>
                  <FormGrid>
                    <label>
                      ID
                      <input value={selectedCluster.id} readOnly />
                    </label>
                    <label>
                      Slug
                      <input value={selectedCluster.slug} readOnly />
                    </label>
                    <label>
                      Название
                      <input
                        value={clusterSettingsForm.name}
                        onChange={(event) => setClusterSettingsForm({ ...clusterSettingsForm, name: event.target.value })}
                      />
                    </label>
                    <label>
                      Статус
                      <select
                        value={clusterSettingsForm.status}
                        onChange={(event) => setClusterSettingsForm({ ...clusterSettingsForm, status: event.target.value })}
                      >
                        <option value="active">active, работает</option>
                        <option value="disabled">disabled, отключен</option>
                      </select>
                    </label>
                    <label>
                      Регион
                      <input
                        value={clusterSettingsForm.region}
                        onChange={(event) => setClusterSettingsForm({ ...clusterSettingsForm, region: event.target.value })}
                        placeholder="например ru-msk-1"
                      />
                    </label>
                    <label>
                      Обновлен
                      <input value={formatDate(selectedCluster.updated_at || selectedCluster.created_at)} readOnly />
                    </label>
                  </FormGrid>
                  <label className="wideLabel">
                    Metadata JSON
                    <textarea
                      value={clusterSettingsForm.metadataJson}
                      onChange={(event) => setClusterSettingsForm({ ...clusterSettingsForm, metadataJson: event.target.value })}
                      rows={8}
                      spellCheck={false}
                    />
                  </label>
                  <button
                    className="primary"
                    disabled={!clusterSettingsForm.name.trim()}
                    onClick={() =>
                      confirmHighRisk("Сохранить базовые настройки кластера") &&
                      void runAction(async () => {
                        const metadata = parseJSONObject(clusterSettingsForm.metadataJson || "{}", "Metadata JSON");
                        await client.updateCluster(selectedCluster.id, {
                          name: clusterSettingsForm.name,
                          status: clusterSettingsForm.status,
                          region: clusterSettingsForm.region || null,
                          metadata,
                        });
                      }, "Настройки кластера сохранены.")
                    }
                  >
                    Сохранить настройки кластера
                  </button>
                </article>

                <article className="card">
                  <h3>Authority и режим изменений</h3>
                  <p className="muted">Эта секция защищает кластер от split-brain: minority/read-only сегменты не должны принимать изменения политик.</p>
                  <div className="stateGrid">
                    <StateLine label="Authority" value={authority?.authority_state || "неизвестно"} />
                    <StateLine label="Mutation mode" value={authority?.mutation_mode || "неизвестно"} />
                    <StateLine label="Term" value={String(authority?.term ?? "н/д")} />
                    <StateLine label="Cluster key" value={shortId(selectedSummary?.cluster_key_fingerprint)} />
                    <StateLine label="Последнее изменение" value={formatDate(authority?.updated_at)} />
                  </div>
                  <FormGrid>
                    <label>
                      Состояние authority
                      <select
                        value={authorityForm.authorityState}
                        onChange={(event) => setAuthorityForm({ ...authorityForm, authorityState: event.target.value })}
                      >
                        <option value="authoritative">authoritative, основной</option>
                        <option value="minority">minority, меньшинство</option>
                        <option value="isolated">isolated, изолирован</option>
                        <option value="recovery">recovery, восстановление</option>
                      </select>
                    </label>
                    <label>
                      Режим изменений
                      <select value={authorityForm.mutationMode} onChange={(event) => setAuthorityForm({ ...authorityForm, mutationMode: event.target.value })}>
                        <option value="normal">normal, обычный</option>
                        <option value="read_only">read_only, только чтение</option>
                        <option value="recovery_override">recovery_override, восстановление</option>
                      </select>
                    </label>
                    <label>
                      Примечание
                      <input value={authorityForm.notes} onChange={(event) => setAuthorityForm({ ...authorityForm, notes: event.target.value })} />
                    </label>
                  </FormGrid>
                  <button
                    disabled={!selectedClusterId}
                    onClick={() =>
                      confirmHighRisk("Изменить authority state кластера") &&
                      void runAction(
                        () =>
                          client.updateClusterAuthority(selectedClusterId, {
                            authorityState: authorityForm.authorityState,
                            mutationMode: authorityForm.mutationMode,
                            notes: authorityForm.notes,
                          }),
                        "Authority кластера обновлен.",
                      )
                    }
                  >
                    Обновить authority
                  </button>
                </article>

                <article className="card">
                  <h3>Safety / quorum</h3>
                  <div className="stateGrid">
                    <StateLine label="Узлы" value={String(selectedSummary?.node_count ?? nodes.length)} />
                    <StateLine label="Healthy" value={String(selectedSummary?.healthy_node_count ?? healthyNodeCount)} />
                    <StateLine label="Pending join" value={String(selectedSummary?.pending_join_count ?? joinRequests.filter((item) => item.status === "pending").length)} />
                    <StateLine label="Последний узел" value={formatDate(selectedSummary?.last_node_seen_at)} />
                  </div>
                  <p className="muted">
                    Минимальный размер, quorum policy и split-brain rules пока не имеют отдельного runtime-переключателя. Сейчас защита выполняется через
                    authority/mutation mode, explicit node approval и аудит.
                  </p>
                </article>

                <article className="card">
                  <h3>Telemetry / testing</h3>
                  <div className="stateGrid">
                    <StateLine label="Telemetry flag" value={platformTestingFlag?.telemetry_enabled ? "включен" : "выключен"} />
                    <StateLine label="Synthetic links" value={platformTestingFlag?.synthetic_links_enabled ? "включены" : "выключены"} />
                    <StateLine label="Хранение истории, часов" value={String(platformTestingFlag?.history_retention_hours ?? "н/д")} />
                  </div>
                  <p className="muted">
                    Это тестовый контур наблюдаемости: heartbeat/telemetry реальные, а связи Fabric сейчас synthetic. Production mesh traffic здесь пока не
                    отображается.
                  </p>
                </article>

                <article className="card">
                  <h3>Storage / updates</h3>
                  <div className="stateGrid">
                    <StateLine label="Version Storage" value="архитектура зафиксирована, runtime не реализован" />
                    <StateLine label="Update cache" value={`${nodesWithRole("update-cache", rolesByNode).length} узл.`} />
                    <StateLine label="File/config cache" value={`${nodesWithRole("file-storage-cache", rolesByNode).length} узл.`} />
                  </div>
                  <p className="muted">
                    Version Storage будет хранить stable/current/candidate и signed artifacts. Сейчас это не production updater runtime.
                  </p>
                </article>

                <article className="card">
                  <h3>Admin endpoints</h3>
                  <div className="stateGrid">
                    <StateLine label="Entry nodes" value={`${nodesWithRole("entry-node", rolesByNode).length} узл.`} />
                    <StateLine label="Relay nodes" value={`${nodesWithRole("relay-node", rolesByNode).length} узл.`} />
                    <StateLine label="Core mesh" value={`${nodesWithRole("core-mesh", rolesByNode).length} узл.`} />
                  </div>
                  <p className="muted">
                    Панель кластера не переезжает автоматически на storage-узел. Cluster Admin Endpoint должен быть назначен отдельной explicit ролью на
                    ingress/admin-capable узле.
                  </p>
                </article>
              </>
            )}
          </section>
        )}

        {activeView === "nodes" && (
          <section className="grid two">
            <article className="card span2">
              <div className="cardHead">
                <div>
                  <h3>{t.nodeManagement}</h3>
                  <p className="muted">
                    Единый краткий список узлов. По умолчанию показан активный кластер; включите общий режим, чтобы увидеть весь инвентарь платформы.
                  </p>
                </div>
                <div className="actions">
                  <label className="checkLine">
                    <input
                      type="checkbox"
                      checked={nodeViewScope === "all"}
                      onChange={(event) => setNodeViewScope(event.target.checked ? "all" : "cluster")}
                    />
                    {t.showAllPlatformNodes}
                  </label>
                  <button
                    className="ghost"
                    onClick={() => {
                      setNodeViewScope("all");
                      setAllNodeSearch("");
                    }}
                  >
                    {t.showAllPlatformNodes}
                  </button>
                </div>
              </div>
              <div className="signalStrip compact">
                <Signal label="Узлы активного кластера" value={String(nodes.length)} />
                <Signal label="Все узлы" value={String(allNodeInventory.length)} />
                <Signal label="Заявки" value={String(pendingJoinCount)} />
                <Signal label="Активные роли" value={String(activeRoleCount)} />
              </div>
              <p className="muted">{t.addNodeText}</p>
            </article>

            <article className="card span2">
              <div className="cardHead">
                <div>
                  <h3>{t.nodeBriefList}</h3>
                  <p className="muted">{t.nodeBriefListHelp}</p>
                </div>
                <span className="pill">{visibleNodeInventory.length}</span>
              </div>
              <FormGrid>
                <label>
                  {t.nodeSearch}
                  <input value={allNodeSearch} onChange={(event) => setAllNodeSearch(event.target.value)} placeholder={t.nodeSearchPlaceholder} />
                </label>
                <label>
                  {t.nodeGroupFilter}
                  <select value={nodeGroupFilterId} onChange={(event) => setNodeGroupFilterId(event.target.value)}>
                    <option value="">{t.allNodeGroups}</option>
                    {nodeGroups.map((group) => (
                      <option key={group.id} value={group.id}>
                        {groupPathLabel(group, nodeGroups)}
                      </option>
                    ))}
                  </select>
                </label>
              </FormGrid>
              <p className="muted">{t.nodeGroupInventoryText}</p>
              <h4>{t.nodeGroupCreatePanel}</h4>
              <FormGrid>
                <label>
                  {t.nodeGroupName}
                  <input value={nodeGroupForm.name} onChange={(event) => setNodeGroupForm({ ...nodeGroupForm, name: event.target.value })} />
                </label>
                <label>
                  {t.parentNodeGroup}
                  <select value={nodeGroupForm.parentGroupId} onChange={(event) => setNodeGroupForm({ ...nodeGroupForm, parentGroupId: event.target.value })}>
                    <option value="">{t.rootNodeGroup}</option>
                    {nodeGroups.map((group) => (
                      <option key={group.id} value={group.id}>
                        {groupPathLabel(group, nodeGroups)}
                      </option>
                    ))}
                  </select>
                </label>
                <label>
                  {t.createNodeGroup}
                  <button
                    className="primary"
                    disabled={!nodeGroupForm.name.trim()}
                    onClick={() =>
                      void runAction(
                        async () => {
                          await client.createNodeGroup(selectedClusterId, {
                            name: nodeGroupForm.name,
                            parentGroupId: nodeGroupForm.parentGroupId || null,
                          });
                          setNodeGroupForm({ name: "", parentGroupId: "" });
                        },
                        t.nodeGroupCreated,
                      )
                    }
                  >
                    {t.createNodeGroup}
                  </button>
                </label>
              </FormGrid>
              <div className="nodeList">
                {visibleNodeTreeRows.map((row) => {
                  if (row.kind === "group") {
                    const isCollapsed = collapsedNodeGroupKeys.includes(row.key);
                    return (
                      <div className="nodeListGroup" key={row.key} style={{ paddingLeft: `${row.depth * 18}px` }}>
                        <div className="nodeListMain">
                          <strong>{row.label}</strong>
                          {row.groupId && <span>{groupPathLabelById(row.groupId, nodeGroups)}</span>}
                        </div>
                        <div className="actions">
                          <span className="pill">{row.count}</span>
                          <button className="ghost" onClick={() => setCollapsedNodeGroupKeys(toggleArrayValue(collapsedNodeGroupKeys, row.key))}>
                            {isCollapsed ? t.expandGroup : t.collapseGroup}
                          </button>
                          {row.groupId && (
                            <button className="ghost" onClick={() => setNodeGroupForm({ name: "", parentGroupId: row.groupId || "" })}>
                              {t.createSubgroup}
                            </button>
                          )}
                        </div>
                      </div>
                    );
                  }
                  const entry = row.entry;
                  const activeMembership = entry.memberships.find((membership) => membership.cluster.id === selectedClusterId);
                  const displayNode = activeMembership?.node || entry.node;
                  const isActiveMember = activeMembership?.node.membership_status === "active";
                  const isRevokedMember = activeMembership?.node.membership_status === "revoked";
                  return (
                    <div className="nodeListRow" key={row.key} style={{ marginLeft: `${row.depth * 18}px` }}>
                      <div className="nodeListMain">
                        <strong>{displayNode.name}</strong>
                        <span>{displayNode.node_key}</span>
                      </div>
                      <Status value={displayNode.health_status} />
                      <span className="muted">{displayNode.reported_version || "версия неизвестна"}</span>
                      <span className="muted">{formatDate(displayNode.last_seen_at)}</span>
                      {activeMembership ? <Status value={activeMembership.node.membership_status} /> : <span className="muted">{t.notMemberOfActiveCluster}</span>}
                      <div className="actions">
                        <button
                          onClick={() => {
                            setNodeInfoDialog(entry);
                            setNodeInfoMode("details");
                          }}
                        >
                          {t.nodeDetails}
                        </button>
                        {isActiveMember ? (
                          <button
                            className="primary"
                            onClick={() => {
                              setNodeInfoDialog(entry);
                              setNodeInfoMode("manage");
                            }}
                          >
                            {t.manageNode}
                          </button>
                        ) : isRevokedMember ? (
                          <span className="muted">{t.revokedMembership}</span>
                        ) : (
                          <button
                            className="primary"
                            onClick={() => {
                              setAttachNodeDialog(entry);
                              setAttachNodeRoles([]);
                            }}
                          >
                            {t.connectExistingNode}
                          </button>
                        )}
                      </div>
                    </div>
                  );
                })}
                {visibleNodeTreeRows.length === 0 && <EmptyState title={t.noNodesTitle} text={t.noNodesByFilter} />}
              </div>
            </article>

            {attachNodeDialog && (
              <div className="modalBackdrop" role="presentation">
                <div className="modalCard" role="dialog" aria-modal="true" aria-labelledby="attach-node-title">
                  <div className="cardHead">
                    <div>
                      <h3 id="attach-node-title">{t.connectExistingNodeTitle}</h3>
                      <p className="muted">{t.connectExistingNodeText}</p>
                    </div>
                    <button className="ghost" onClick={() => setAttachNodeDialog(null)}>
                      {t.cancel}
                    </button>
                  </div>
                  <div className="stateList">
                    <StateLine label="Узел" value={attachNodeDialog.node.name} />
                    <StateLine label="Node key" value={attachNodeDialog.node.node_key} />
                    <StateLine label={t.activeCluster} value={selectedCluster?.name || selectedClusterId} />
                  </div>
                  <div className="checkGrid">
                    {roleOptions.map((role) => (
                      <label className="checkLine" key={role}>
                        <input type="checkbox" checked={attachNodeRoles.includes(role)} onChange={() => setAttachNodeRoles(toggleArrayValue(attachNodeRoles, role))} />
                        {role}
                      </label>
                    ))}
                  </div>
                  <div className="actions">
                    <button
                      className="primary"
                      onClick={() =>
                        void runAction(
                          async () => {
                            await client.attachExistingNode(selectedClusterId, attachNodeDialog.node.id, attachNodeRoles);
                            setAttachNodeDialog(null);
                            setAttachNodeRoles([]);
                            setNodeViewScope("cluster");
                          },
                          "Узел подключен к активному кластеру.",
                        )
                      }
                    >
                      {t.connectWithRoles}
                    </button>
                    <button onClick={() => setAttachNodeDialog(null)}>{t.cancel}</button>
                  </div>
                </div>
              </div>
            )}

            {nodeInfoDialog &&
              (() => {
                const activeMembership = nodeInfoDialog.memberships.find((membership) => membership.cluster.id === selectedClusterId);
                const node = activeMembership?.node || nodeInfoDialog.node;
                const latestHeartbeat = activeMembership ? (heartbeatsByNode[node.id] || [])[0] : undefined;
                const activeRoles = activeMembership ? (rolesByNode[node.id] || []).filter((role) => role.status === "active") : [];
                const desiredWorkloads = activeMembership ? desiredWorkloadsByNode[node.id] || [] : [];
                const observedWorkloads = activeMembership ? workloadsByNode[node.id] || [] : [];
                return (
                  <div className="modalBackdrop" role="presentation">
                    <div className="modalCard wide" role="dialog" aria-modal="true" aria-labelledby="node-info-title">
                      <div className="cardHead">
                        <div>
                          <h3 id="node-info-title">
                            {nodeInfoMode === "manage" ? t.manageNode : t.nodeDetails}: {node.name}
                          </h3>
                          <p className="muted">{node.node_key}</p>
                        </div>
                        <button
                          className="ghost"
                          onClick={() => {
                            setNodeInfoDialog(null);
                            setNodeInfoMode("details");
                          }}
                        >
                          {t.close}
                        </button>
                      </div>

                      <section className="nodePanel">
                        <h4>{t.nodeIdentity}</h4>
                        <div className="stateList">
                          <StateLine label="Node ID" value={shortId(node.id)} />
                          <StateLine label="Ключ узла" value={node.node_key} />
                          <StateLine label="Тип владения" value={statusLabel(node.ownership_type)} />
                          <StateLine label="Owner org" value={shortId(node.owner_organization_id)} />
                          <StateLine label="Регистрация" value={statusLabel(node.registration_status)} />
                          <StateLine label="Здоровье" value={statusLabel(node.health_status)} />
                          <StateLine label="Версия" value={node.reported_version || "неизвестно"} />
                          <StateLine label="Последний сигнал" value={formatDate(node.last_seen_at)} />
                        </div>
                      </section>

                      <section className="nodePanel">
                        <h4>{t.clusterMemberships}</h4>
                        <div className="membershipList">
                          {nodeInfoDialog.memberships.map((membership) => (
                            <span key={membership.cluster.id} className={membership.cluster.id === selectedClusterId ? "pill good" : "pill"}>
                              {membership.cluster.name}: {statusLabel(membership.node.membership_status)}
                            </span>
                          ))}
                        </div>
                      </section>

                      {activeMembership ? (
                        <>
                          <section className="nodePanel">
                            <h4>{t.activeClusterScope}</h4>
                            <div className="stateList">
                              <StateLine label="Участие" value={statusLabel(node.membership_status)} />
                              <StateLine label="Сегмент" value={statusLabel(node.partition_state)} />
                              <StateLine label="Группа" value={node.node_group_name || t.ungroupedNodes} />
                              <StateLine label="Ролей" value={String(activeRoles.length)} />
                              <StateLine label="Desired-сервисов" value={String(desiredWorkloads.length)} />
                              <StateLine label="Observed-сервисов" value={String(observedWorkloads.length)} />
                            </div>
                          </section>

                          {nodeInfoMode === "details" && (
                            <>
                          <section className="nodePanel">
                            <h4>{t.nodeRoles}</h4>
                            <div className="serviceTags">
                              {activeRoles.length === 0 && <p className="muted">{t.noRoles}</p>}
                              {activeRoles.map((role) => (
                                <div className="serviceTag" key={role.id}>
                                  <strong>{role.role}</strong>
                                  <span>{role.organization_id ? `organization: ${shortId(role.organization_id)}` : "cluster-wide"}</span>
                                  <small>{formatDate(role.assigned_at)}</small>
                                  <span className={`pill ${capabilityPillTone(role.role, latestHeartbeat)}`}>{capabilityLabel(role.role, latestHeartbeat, t)}</span>
                                </div>
                              ))}
                            </div>
                          </section>

                          <section className="nodePanel">
                            <h4>{t.desiredServices}</h4>
                            <div className="serviceTags">
                              {desiredWorkloads.length === 0 && <p className="muted">{t.noServices}</p>}
                              {desiredWorkloads.map((workload) => (
                                <div className="serviceTag" key={`${workload.service_type}-${workload.runtime_mode}`}>
                                  <strong>{workload.service_type}</strong>
                                  <span>
                                    {statusLabel(workload.desired_state)} / {workload.runtime_mode}
                                  </span>
                                  <small>{workload.version || "версия не закреплена"}</small>
                                </div>
                              ))}
                            </div>
                          </section>

                          <section className="nodePanel">
                            <h4>{t.observedServices}</h4>
                            <div className="serviceTags">
                              {observedWorkloads.length === 0 && <p className="muted">{t.noServices}</p>}
                              {observedWorkloads.map((workload) => (
                                <div className="serviceTag" key={workload.id}>
                                  <strong>{workload.service_type}</strong>
                                  <span>
                                    {statusLabel(workload.reported_state)} / {workload.runtime_mode}
                                  </span>
                                  <small>{formatDate(workload.observed_at)}</small>
                                </div>
                              ))}
                            </div>
                          </section>

                          <section className="nodePanel">
                            <h4>{t.nodeTelemetry}</h4>
                            <TelemetryStrip items={telemetryByNode[node.id] || []} emptyText={t.noTelemetry} />
                          </section>

                          <section className="nodePanel">
                            <h4>{t.recentHeartbeats}</h4>
                            <DataTable
                              columns={["состояние", "версия", "mesh recovery", "mesh intents", "rv leases", "path decisions", "route gen", "route health", "наблюдение"]}
                              rows={(heartbeatsByNode[node.id] || []).slice(0, 5).map((heartbeat) => [
                                heartbeat.health_status,
                                heartbeat.reported_version || "неизвестно",
                                meshRecoverySummary(heartbeat),
                                meshConnectionIntentSummary(heartbeat),
                                meshRendezvousLeaseSummary(heartbeat),
                                meshRoutePathDecisionSummary(heartbeat),
                                meshRouteGenerationSummary(heartbeat),
                                meshRouteHealthConfigSummary(heartbeat),
                                formatDate(heartbeat.observed_at),
                              ])}
                            />
                          </section>
                            </>
                          )}

                          {nodeInfoMode === "manage" && (
                          <section className="nodePanel">
                            <h4>{t.nodeFunctions}</h4>
                            <p className="muted">{t.nodeFunctionsText}</p>
                            <label className="wideLabel">
                              {t.organizationScopeForEnable}
                              <input value={roleOrgScope} onChange={(event) => setRoleOrgScope(event.target.value)} placeholder={t.clusterWideRolePlaceholder} />
                            </label>
                            <div className="functionList">
                              {roleOptions.map((role) => {
                                const activeRole = activeRoles.find((assignment) => assignment.role === role);
                                const desired = desiredWorkloads.find((workload) => workload.service_type === role);
                                const observed = observedWorkloads.find((workload) => workload.service_type === role);
                                const capabilityTone = capabilityPillTone(role, latestHeartbeat);
                                const desiredState = desired?.desired_state || "disabled";
                                const observedState = observed?.reported_state || "missing";
                                const enabled = Boolean(activeRole) && desiredState === "enabled";
                                return (
                                  <div className="functionRow" key={role}>
                                    <div className="nodeListMain">
                                      <strong>{role}</strong>
                                      <span>{capabilityOptionLabel(role, latestHeartbeat, language)}</span>
                                    </div>
                                    <span className={`pill ${activeRole ? "good" : ""}`}>{activeRole ? t.permissionGranted : t.permissionDenied}</span>
                                    <Status value={desiredState} />
                                    <Status value={observedState} />
                                    <span className={`pill ${capabilityTone}`}>{capabilityLabel(role, latestHeartbeat, t)}</span>
                                    <div className="actions">
                                      <button
                                        className={enabled ? "" : "primary"}
                                        disabled={enabled}
                                        onClick={() =>
                                          void runAction(async () => {
                                            if (!activeRole) {
                                              await client.setRoleStatus(selectedClusterId, node.id, role, "active", roleOrgScope || undefined);
                                            }
                                            await client.setDesiredWorkload(selectedClusterId, node.id, role, {
                                              desiredState: "enabled",
                                              runtimeMode: "container",
                                              config: {},
                                              environment: {},
                                            });
                                          }, `${role}: функция включена.`)
                                        }
                                      >
                                        {t.enableFunction}
                                      </button>
                                      <button
                                        disabled={!activeRole && desiredState !== "enabled"}
                                        onClick={() =>
                                          void runAction(async () => {
                                            await client.setDesiredWorkload(selectedClusterId, node.id, role, {
                                              desiredState: "disabled",
                                              runtimeMode: desired?.runtime_mode || "container",
                                              config: desired?.config || {},
                                              environment: desired?.environment || {},
                                            });
                                            if (activeRole) {
                                              await client.setRoleStatus(selectedClusterId, node.id, role, "disabled", activeRole.organization_id || undefined);
                                            }
                                          }, `${role}: функция выключена.`)
                                        }
                                      >
                                        {t.disableFunction}
                                      </button>
                                    </div>
                                  </div>
                                );
                              })}
                            </div>
                            <div className="actions">
                              <select
                                value={node.node_group_id || ""}
                                onChange={(event) =>
                                  void runAction(
                                    () => client.assignNodeGroup(selectedClusterId, node.id, event.target.value || null),
                                    event.target.value ? "Узел перемещен в группу." : "Узел убран из группы.",
                                  )
                                }
                              >
                                <option value="">{t.ungroupedNodes}</option>
                                {nodeGroups.map((group) => (
                                  <option key={group.id} value={group.id}>
                                    {groupPathLabel(group, nodeGroups)}
                                  </option>
                                ))}
                              </select>
                            </div>
                            <div className="actions">
                              <button
                                onClick={() =>
                                  confirmHighRisk(`Отключить участие узла ${node.name}`) &&
                                  void runAction(
                                    () => client.disableMembership(selectedClusterId, node.id, "Отключено из панели владельца платформы."),
                                    "Участие узла отключено.",
                                  )
                                }
                              >
                                Отключить участие
                              </button>
                              <button
                                className="danger"
                                onClick={() =>
                                  confirmHighRisk(`Отозвать identity узла ${node.name}`) &&
                                  void runAction(
                                    () => client.revokeNodeIdentity(selectedClusterId, node.id, "Отозвано из панели владельца платформы."),
                                    "Identity узла отозван.",
                                  )
                                }
                              >
                                Отозвать identity
                              </button>
                            </div>
                          </section>
                          )}
                        </>
                      ) : (
                        <section className="nodePanel">
                          <h4>{t.noActiveClusterMembership}</h4>
                          <div className="actions">
                            <button
                              className="primary"
                              onClick={() => {
                                setAttachNodeDialog(nodeInfoDialog);
                                setAttachNodeRoles([]);
                                setNodeInfoDialog(null);
                              }}
                            >
                              {t.connectExistingNode}
                            </button>
                          </div>
                        </section>
                      )}
                    </div>
                  </div>
                );
              })()}

            {false && (nodeViewScope === "all" ? (
              <article className="card span2">
                <h3>{t.allNodes}</h3>
                <p className="muted">{t.nodeGlobalInventoryText}</p>
                <FormGrid>
                  <label>
                    {t.nodeSearch}
                    <input value={allNodeSearch} onChange={(event) => setAllNodeSearch(event.target.value)} placeholder="имя, ключ, кластер, статус" />
                  </label>
                  <label>
                    {t.groupNodesBy}
                    <select value={allNodeGroupBy} onChange={(event) => setAllNodeGroupBy(event.target.value as typeof allNodeGroupBy)}>
                      <option value="membership">{t.groupByMembership}</option>
                      <option value="health">{t.groupByHealth}</option>
                      <option value="ownership">{t.groupByOwnership}</option>
                      <option value="cluster_count">{t.groupByClusterCount}</option>
                    </select>
                  </label>
                </FormGrid>
                <div className="stack">
                  {groupedAllNodeInventory.map((group) => (
                    <section className="nodePanel" key={group.label}>
                      <div className="cardHead">
                        <h4>{group.label}</h4>
                        <span className="pill">{group.items.length}</span>
                      </div>
                      <DataTable
                        columns={["узел", "ключ", t.currentClusterMembership, t.clusterMemberships, "здоровье", "версия", "последний сигнал", "действие"]}
                        rows={group.items.map((entry) => {
                          const { node, memberships } = entry;
                          const activeMembership = memberships.find((membership) => membership.cluster.id === selectedClusterId);
                          const isActiveMember = activeMembership?.node.membership_status === "active";
                          const isRevokedMember = activeMembership?.node.membership_status === "revoked";
                          return [
                            node.name,
                            node.node_key,
                            activeMembership ? <Status value={activeMembership.node.membership_status} /> : <span className="muted">{t.notMemberOfActiveCluster}</span>,
                            <div className="membershipList">
                              {memberships.map((membership) => (
                                <span key={`${membership.cluster.id}-${membership.node.id}`} className={membership.cluster.id === selectedClusterId ? "pill good" : "pill"}>
                                  {membership.cluster.name}: {statusLabel(membership.node.membership_status)}
                                </span>
                              ))}
                            </div>,
                            statusLabel(node.health_status),
                            node.reported_version || "неизвестно",
                            formatDate(node.last_seen_at),
                            <div className="actions" key={`${selectedClusterId}-${node.id}`}>
                              {isActiveMember ? (
                                <button
                                  onClick={() => {
                                    setNodeViewScope("cluster");
                                  }}
                                >
                                  {t.manageInCluster}
                                </button>
                              ) : isRevokedMember ? (
                                <span className="muted">{t.revokedMembership}</span>
                              ) : (
                                <button
                                  className="primary"
                                  onClick={() => {
                                    setAttachNodeDialog(entry);
                                    setAttachNodeRoles([]);
                                  }}
                                >
                                  {t.connectExistingNode}
                                </button>
                              )}
                            </div>,
                          ];
                        })}
                      />
                    </section>
                  ))}
                  {groupedAllNodeInventory.length === 0 && <EmptyState title="Нет узлов" text="По текущему фильтру узлы не найдены." />}
                </div>
                {attachNodeDialog && (
                  <div className="modalBackdrop" role="presentation">
                    <div className="modalCard" role="dialog" aria-modal="true" aria-labelledby="attach-node-title">
                      <div className="cardHead">
                        <div>
                          <h3 id="attach-node-title">{t.connectExistingNodeTitle}</h3>
                          <p className="muted">{t.connectExistingNodeText}</p>
                        </div>
                        <button className="ghost" onClick={() => setAttachNodeDialog(null)}>
                          {t.cancel}
                        </button>
                      </div>
                      <div className="stateList">
                        <StateLine label="Узел" value={attachNodeDialog!.node.name} />
                        <StateLine label="Node key" value={attachNodeDialog!.node.node_key} />
                        <StateLine label={t.activeCluster} value={selectedCluster?.name || selectedClusterId} />
                      </div>
                      <div className="checkGrid">
                        {roleOptions.map((role) => (
                          <label className="checkLine" key={role}>
                            <input
                              type="checkbox"
                              checked={attachNodeRoles.includes(role)}
                              onChange={() => setAttachNodeRoles(toggleArrayValue(attachNodeRoles, role))}
                            />
                            {role}
                          </label>
                        ))}
                      </div>
                      <div className="actions">
                        <button
                          className="primary"
                          onClick={() =>
                            void runAction(
                              async () => {
                                await client.attachExistingNode(selectedClusterId, attachNodeDialog!.node.id, attachNodeRoles);
                                setAttachNodeDialog(null);
                                setAttachNodeRoles([]);
                                setNodeViewScope("cluster");
                              },
                              "Узел подключен к активному кластеру.",
                            )
                          }
                        >
                          {t.connectWithRoles}
                        </button>
                        <button onClick={() => setAttachNodeDialog(null)}>{t.cancel}</button>
                      </div>
                    </div>
                  </div>
                )}
              </article>
            ) : (
              <>
            <article className="card span2">
              <h3>{t.testMode}</h3>
              <p className="muted">{t.testModeText}</p>
              <div className="actions">
                <button
                  className={platformTestingFlag?.telemetry_enabled ? "primary" : ""}
                  onClick={() =>
                    void runAction(
                      () =>
                        client.updateFabricTestingFlag({
                          scopeType: "platform",
                          enabled: true,
                          telemetryEnabled: !platformTestingFlag?.telemetry_enabled,
                          syntheticLinksEnabled: Boolean(platformTestingFlag?.synthetic_links_enabled),
                          historyRetentionHours: platformTestingFlag?.history_retention_hours || 24,
                        }),
                      platformTestingFlag?.telemetry_enabled ? "Тестовая телеметрия платформы выключена." : "Тестовая телеметрия платформы включена.",
                    )
                  }
                >
                  {t.enableTelemetry}: {platformTestingFlag?.telemetry_enabled ? "ВКЛ" : "ВЫКЛ"}
                </button>
                <button
                  className={platformTestingFlag?.synthetic_links_enabled ? "primary" : ""}
                  onClick={() =>
                    void runAction(
                      () =>
                        client.updateFabricTestingFlag({
                          scopeType: "platform",
                          enabled: true,
                          telemetryEnabled: Boolean(platformTestingFlag?.telemetry_enabled),
                          syntheticLinksEnabled: !platformTestingFlag?.synthetic_links_enabled,
                          historyRetentionHours: platformTestingFlag?.history_retention_hours || 24,
                        }),
                      platformTestingFlag?.synthetic_links_enabled ? "Тестовые связи выключены." : "Тестовые связи включены.",
                    )
                  }
                >
                  {t.enableSyntheticLinks}: {platformTestingFlag?.synthetic_links_enabled ? "ВКЛ" : "ВЫКЛ"}
                </button>
              </div>
              <section className="nodePanel">
                <h4>{t.organizationTestFlag}</h4>
                <p className="muted">
                  Флаг уровня организации нужен для безопасной проверки телеметрии и истории в tenant scope. Он не раскрывает внутреннюю topology
                  organization-панелям.
                </p>
                <FormGrid>
                  <label>
                    {t.organizationId}
                    <input value={testingOrgId} onChange={(event) => setTestingOrgId(event.target.value)} placeholder="UUID организации" />
                  </label>
                  <label className="checkLine">
                    <input
                      type="checkbox"
                      checked={testingOrgDraft.telemetry}
                      onChange={(event) => setTestingOrgDraft({ ...testingOrgDraft, telemetry: event.target.checked })}
                    />
                    {t.enableTelemetry}
                  </label>
                  <label className="checkLine">
                    <input
                      type="checkbox"
                      checked={testingOrgDraft.links}
                      onChange={(event) => setTestingOrgDraft({ ...testingOrgDraft, links: event.target.checked })}
                    />
                    {t.enableSyntheticLinks}
                  </label>
                </FormGrid>
                <div className="actions">
                  <button
                    disabled={!testingOrgId}
                    onClick={() =>
                      void runAction(
                        () =>
                          client.updateFabricTestingFlag({
                            scopeType: "organization",
                            scopeId: testingOrgId,
                            clusterId: selectedClusterId,
                            enabled: true,
                            telemetryEnabled: testingOrgDraft.telemetry,
                            syntheticLinksEnabled: testingOrgDraft.links,
                            historyRetentionHours: organizationTestingFlag?.history_retention_hours || 24,
                          }),
                        "Флаг тестирования организации сохранен.",
                      )
                    }
                  >
                    {t.saveOrganizationFlag}
                  </button>
                  {organizationTestingFlag && <Status value={organizationTestingFlag?.enabled ? "enabled" : "disabled"} />}
                </div>
              </section>
            </article>
            <article className="card span2">
              <div className="cardHead">
                <div>
                  <h3>{t.nodeGroups}</h3>
                  <p className="muted">
                    Группы принадлежат активному кластеру и могут быть вложенными. Один узел может быть в другой группе в другом кластере.
                  </p>
                </div>
                <span className="pill">{nodeGroups.length}</span>
              </div>
              <FormGrid>
                <label>
                  {t.nodeGroupName}
                  <input value={nodeGroupForm.name} onChange={(event) => setNodeGroupForm({ ...nodeGroupForm, name: event.target.value })} />
                </label>
                <label>
                  {t.parentNodeGroup}
                  <select
                    value={nodeGroupForm.parentGroupId}
                    onChange={(event) => setNodeGroupForm({ ...nodeGroupForm, parentGroupId: event.target.value })}
                  >
                    <option value="">{t.rootNodeGroup}</option>
                    {nodeGroups.map((group) => (
                      <option key={group.id} value={group.id}>
                        {groupPathLabel(group, nodeGroups)}
                      </option>
                    ))}
                  </select>
                </label>
              </FormGrid>
              <div className="actions">
                <button
                  className="primary"
                  disabled={!nodeGroupForm.name.trim()}
                  onClick={() =>
                    void runAction(
                      async () => {
                        await client.createNodeGroup(selectedClusterId, {
                          name: nodeGroupForm.name,
                          parentGroupId: nodeGroupForm.parentGroupId || null,
                        });
                        setNodeGroupForm({ name: "", parentGroupId: "" });
                      },
                      "Группа узлов создана.",
                    )
                  }
                >
                  {t.createNodeGroup}
                </button>
              </div>
              <NodeGroupTree groups={nodeGroups} nodes={nodes} labels={t} />
            </article>
            {nodes.map((node) => {
              const latestHeartbeat = (heartbeatsByNode[node.id] || [])[0];
              const activeRoles = (rolesByNode[node.id] || []).filter((role) => role.status === "active");
              const desiredWorkloads = desiredWorkloadsByNode[node.id] || [];
              const observedWorkloads = workloadsByNode[node.id] || [];
              return (
              <article className="card nodeCard" key={node.id}>
                <div className="cardHead">
                  <div>
                    <h3>{node.name}</h3>
                    <p className="muted">{node.node_key}</p>
                  </div>
                  <Status value={node.health_status} />
                </div>
                <section className="nodePanel">
                  <h4>{t.nodeIdentity}</h4>
                  <div className="stateList">
                    <StateLine label="Node ID" value={shortId(node.id)} />
                    <StateLine label="Ключ узла" value={node.node_key} />
                    <StateLine label="Тип владения" value={statusLabel(node.ownership_type)} />
                    <StateLine label="Owner org" value={shortId(node.owner_organization_id)} />
                    <StateLine label="Регистрация" value={statusLabel(node.registration_status)} />
                  </div>
                </section>
                <section className="nodePanel">
                  <h4>{t.activeClusterScope}</h4>
                  <p className="muted">{t.activeClusterScopeText}</p>
                  <div className="stateList">
                    <StateLine label="Участие" value={statusLabel(node.membership_status)} />
                    <StateLine label="Сегмент" value={statusLabel(node.partition_state)} />
                    <StateLine label="Здоровье" value={statusLabel(node.health_status)} />
                    <StateLine label="Группа" value={node.node_group_name || t.ungroupedNodes} />
                    <StateLine label="Версия" value={node.reported_version || "неизвестно"} />
                    <StateLine label="Последний сигнал" value={formatDate(node.last_seen_at)} />
                    <StateLine label="Ролей в кластере" value={String(activeRoles.length)} />
                    <StateLine label="Desired-сервисов" value={String(desiredWorkloads.length)} />
                    <StateLine label="Observed-сервисов" value={String(observedWorkloads.length)} />
                  </div>
                </section>
                <section className="nodePanel">
                  <h4>{t.nodeRoles}</h4>
                  <div className="serviceTags">
                    {activeRoles.length === 0 && <p className="muted">{t.noRoles}</p>}
                    {activeRoles.map((role) => (
                        <div className="serviceTag" key={role.id}>
                          <strong>{role.role}</strong>
                          <span>{role.organization_id ? `organization: ${shortId(role.organization_id)}` : "cluster-wide"}</span>
                          <small>{formatDate(role.assigned_at)}</small>
                          <span className={`pill ${capabilityPillTone(role.role, latestHeartbeat)}`}>
                            {capabilityLabel(role.role, latestHeartbeat, t)}
                          </span>
                        </div>
                      ))}
                  </div>
                </section>
                <section className="nodePanel">
                  <h4>{t.desiredServices}</h4>
                  <div className="serviceTags">
                    {desiredWorkloads.length === 0 && <p className="muted">{t.noServices}</p>}
                    {desiredWorkloads.map((workload) => (
                      <div className="serviceTag" key={`${workload.service_type}-${workload.runtime_mode}`}>
                        <strong>{workload.service_type}</strong>
                        <span>{statusLabel(workload.desired_state)} / {workload.runtime_mode}</span>
                        <small>{workload.version || "версия не закреплена"}</small>
                        <span className={`pill ${capabilityPillTone(workload.service_type, latestHeartbeat)}`}>
                          {capabilityLabel(workload.service_type, latestHeartbeat, t)}
                        </span>
                      </div>
                    ))}
                  </div>
                </section>
                <section className="nodePanel">
                  <h4>{t.observedServices}</h4>
                  <div className="serviceTags">
                    {observedWorkloads.length === 0 && <p className="muted">{t.noServices}</p>}
                    {observedWorkloads.map((workload) => (
                      <div className="serviceTag" key={workload.id}>
                        <strong>{workload.service_type}</strong>
                        <span>{statusLabel(workload.reported_state)} / {workload.runtime_mode}</span>
                        <small>{formatDate(workload.observed_at)}</small>
                      </div>
                    ))}
                  </div>
                </section>
                <section className="nodePanel">
                  <h4>{t.nodeManagement}</h4>
                  <div className="actions">
                    <select
                      value={nodeRoleDrafts[node.id] || ""}
                      onChange={(event) => setNodeRoleDrafts({ ...nodeRoleDrafts, [node.id]: event.target.value })}
                    >
                      <option value="">Роль...</option>
                      {roleOptions.map((role) => (
                        <option key={role} value={role}>
                          {role} — {capabilityOptionLabel(role, latestHeartbeat, language)}
                        </option>
                      ))}
                    </select>
                    <button
                      disabled={!nodeRoleDrafts[node.id]}
                      onClick={() =>
                        void runAction(
                          () => client.assignRole(selectedClusterId, node.id, nodeRoleDrafts[node.id], roleOrgScope || undefined),
                          "Роль назначена.",
                        )
                      }
                    >
                      Назначить роль
                    </button>
                    <select
                      value={nodeWorkloadDrafts[node.id] || ""}
                      onChange={(event) => setNodeWorkloadDrafts({ ...nodeWorkloadDrafts, [node.id]: event.target.value })}
                    >
                      <option value="">Сервис...</option>
                      {roleOptions.map((role) => (
                        <option key={role} value={role}>
                          {role} — {capabilityOptionLabel(role, latestHeartbeat, language)}
                        </option>
                      ))}
                    </select>
                    <button
                      disabled={!nodeWorkloadDrafts[node.id]}
                      onClick={() =>
                        void runAction(
                          () =>
                            client.setDesiredWorkload(selectedClusterId, node.id, nodeWorkloadDrafts[node.id], {
                              desiredState: "enabled",
                              runtimeMode: "container",
                              config: {},
                              environment: {},
                            }),
                          "Желаемое состояние сервиса включено.",
                        )
                      }
                    >
                      Включить сервис
                    </button>
                    <button
                      disabled={!nodeWorkloadDrafts[node.id]}
                      onClick={() =>
                        void runAction(
                          () =>
                            client.setDesiredWorkload(selectedClusterId, node.id, nodeWorkloadDrafts[node.id], {
                              desiredState: "disabled",
                              runtimeMode: "container",
                              config: {},
                              environment: {},
                            }),
                          "Желаемое состояние сервиса выключено.",
                        )
                      }
                    >
                      Выключить сервис
                    </button>
                    <select
                      value={node.node_group_id || ""}
                      onChange={(event) =>
                        void runAction(
                          () => client.assignNodeGroup(selectedClusterId, node.id, event.target.value || null),
                          event.target.value ? "Узел перемещен в группу." : "Узел убран из группы.",
                        )
                      }
                    >
                      <option value="">{t.ungroupedNodes}</option>
                      {nodeGroups.map((group) => (
                        <option key={group.id} value={group.id}>
                          {groupPathLabel(group, nodeGroups)}
                        </option>
                      ))}
                    </select>
                  </div>
                </section>
                <section className="nodePanel">
                  <h4>{t.testMode}</h4>
                  <div className="actions">
                    <label className="checkLine">
                      <input
                        type="checkbox"
                        checked={nodeTestingDrafts[node.id]?.telemetry ?? true}
                        onChange={(event) =>
                          setNodeTestingDrafts({
                            ...nodeTestingDrafts,
                            [node.id]: { telemetry: event.target.checked, links: nodeTestingDrafts[node.id]?.links ?? true },
                          })
                        }
                      />
                      {t.enableTelemetry}
                    </label>
                    <label className="checkLine">
                      <input
                        type="checkbox"
                        checked={nodeTestingDrafts[node.id]?.links ?? true}
                        onChange={(event) =>
                          setNodeTestingDrafts({
                            ...nodeTestingDrafts,
                            [node.id]: { telemetry: nodeTestingDrafts[node.id]?.telemetry ?? true, links: event.target.checked },
                          })
                        }
                      />
                      {t.enableSyntheticLinks}
                    </label>
                    <button
                      onClick={() =>
                        void runAction(
                          () =>
                            client.updateFabricTestingFlag({
                              scopeType: "node",
                              scopeId: node.id,
                              clusterId: selectedClusterId,
                              enabled: true,
                              telemetryEnabled: nodeTestingDrafts[node.id]?.telemetry ?? true,
                              syntheticLinksEnabled: nodeTestingDrafts[node.id]?.links ?? true,
                              historyRetentionHours: 24,
                            }),
                          "Флаг тестирования узла сохранен.",
                        )
                      }
                    >
                      {t.saveTestFlag}
                    </button>
                  </div>
                </section>
                <section className="nodePanel">
                  <h4>{t.nodeTelemetry}</h4>
                  <TelemetryStrip items={telemetryByNode[node.id] || []} emptyText={t.noTelemetry} />
                </section>
                <section className="nodePanel">
                  <h4>{t.recentHeartbeats}</h4>
                  <DataTable
                    columns={["состояние", "версия", "mesh recovery", "mesh intents", "rv leases", "path decisions", "route gen", "route health", "наблюдение"]}
                    rows={(heartbeatsByNode[node.id] || []).slice(0, 5).map((heartbeat) => [
                      heartbeat.health_status,
                      heartbeat.reported_version || "неизвестно",
                      meshRecoverySummary(heartbeat),
                      meshConnectionIntentSummary(heartbeat),
                      meshRendezvousLeaseSummary(heartbeat),
                      meshRoutePathDecisionSummary(heartbeat),
                      meshRouteGenerationSummary(heartbeat),
                      meshRouteHealthConfigSummary(heartbeat),
                      formatDate(heartbeat.observed_at),
                    ])}
                  />
                </section>
                <div className="actions">
                  <button
                    onClick={() =>
                      confirmHighRisk(`Отключить участие узла ${node.name}`) &&
                      void runAction(
                        () => client.disableMembership(selectedClusterId, node.id, "Отключено из панели владельца платформы."),
                        "Участие узла отключено.",
                      )
                    }
                  >
                    Отключить участие
                  </button>
                  <button
                    className="danger"
                    onClick={() =>
                      confirmHighRisk(`Отозвать identity узла ${node.name}`) &&
                      void runAction(
                        () => client.revokeNodeIdentity(selectedClusterId, node.id, "Отозвано из панели владельца платформы."),
                        "Identity узла отозван.",
                      )
                    }
                  >
                    Отозвать identity
                  </button>
                </div>
              </article>
              );
            })}
            {nodes.length === 0 && <EmptyState title="Нет узлов" text="Одобренные node-agent появятся здесь." />}
              </>
            ))}
          </section>
        )}

        {activeView === "enrollment" && (
          <section className="grid two">
            <article className="card">
              <h3>{t.joinTokenTitle}</h3>
              <p className="muted">{t.joinTokenText}</p>
              <FormGrid>
                <label>
                  {t.ttlHours}
                  <input
                    type="number"
                    min={1}
                    max={720}
                    value={joinTokenForm.ttlHours}
                    onChange={(event) => setJoinTokenForm({ ...joinTokenForm, ttlHours: Number(event.target.value) })}
                  />
                  <small>{t.ttlHelp}</small>
                </label>
                <label>
                  {t.maxUses}
                  <input
                    type="number"
                    min={1}
                    max={100}
                    value={joinTokenForm.maxUses}
                    onChange={(event) => setJoinTokenForm({ ...joinTokenForm, maxUses: Number(event.target.value) })}
                  />
                  <small>{t.maxUsesHelp}</small>
                </label>
                <label>
                  {t.nodeOwnership}
                  <select
                    value={joinTokenForm.ownershipType}
                    onChange={(event) => setJoinTokenForm({ ...joinTokenForm, ownershipType: event.target.value })}
                  >
                    <option value="platform_managed">platform_managed, управляется платформой</option>
                    <option value="customer_managed">customer_managed, управляется клиентом</option>
                  </select>
                </label>
                <label>
                  {t.tokenPurpose}
                  <input
                    value={joinTokenForm.purpose}
                    onChange={(event) => setJoinTokenForm({ ...joinTokenForm, purpose: event.target.value })}
                    placeholder="например: стартовый entry-node в ru-msk-1"
                  />
                </label>
              </FormGrid>
              <section className="nodePanel">
                <h4>{t.suggestedRoles}</h4>
                <p className="muted">
                  Роли можно назначить узлу после approval. Здесь мы задаем безопасную ожидаемую область token, чтобы оператор видел назначение пропуска.
                </p>
                <div className="checkGrid">
                  {roleOptions.map((role) => (
                    <label className="checkLine" key={role}>
                      <input
                        type="checkbox"
                        checked={joinTokenForm.roles.includes(role)}
                        onChange={() => setJoinTokenForm({ ...joinTokenForm, roles: toggleArrayValue(joinTokenForm.roles, role) })}
                      />
                      {role}
                    </label>
                  ))}
                </div>
              </section>
              <details>
                <summary>{t.generatedScope}</summary>
                <p className="muted">{t.generatedScopeHelp}</p>
                <pre className="codePreview">{JSON.stringify(joinTokenScope, null, 2)}</pre>
              </details>
              <p className="muted">{t.manualApprovalRequired}.</p>
              <button
                className="primary"
                disabled={!selectedClusterId}
                onClick={() =>
                  void runAction(async () => {
                    const token = await client.createJoinToken(selectedClusterId, {
                      ttlHours: joinTokenForm.ttlHours,
                      maxUses: joinTokenForm.maxUses,
                      scope: joinTokenScope,
                    });
                    setLastJoinToken(token);
                  }, "Join token создан.")
                }
              >
                Создать token
              </button>
              {lastJoinToken && (
                <div className="secretOnce">
                  <strong>Исходный token, возвращается один раз</strong>
                  <code>{lastJoinToken.token}</code>
                  <span className="muted">Authority key: {shortId(lastJoinToken.authority_signature?.key_fingerprint)}</span>
                </div>
              )}
            </article>

            <article className="card">
              <h3>Заявки на подключение</h3>
              <div className="stack">
                {joinRequests.map((request) => (
                  <div className="requestCard" key={request.id}>
                    <div>
                      <strong>{request.node_name}</strong>
                      <p>{request.node_fingerprint}</p>
                      <Status value={request.status} />
                      {request.approval_signature?.key_fingerprint && (
                        <small className="muted">approval key {shortId(request.approval_signature.key_fingerprint)}</small>
                      )}
                    </div>
                    <div className="actions">
                      <button
                        disabled={request.status !== "pending"}
                        onClick={() => void runAction(() => client.approveJoinRequest(selectedClusterId, request.id), "Заявка одобрена.")}
                      >
                        Одобрить
                      </button>
                      <button
                        disabled={request.status !== "pending"}
                        onClick={() =>
                          void runAction(
                            () => client.rejectJoinRequest(selectedClusterId, request.id, "Отклонено из панели владельца платформы."),
                            "Заявка отклонена.",
                          )
                        }
                      >
                        Отклонить
                      </button>
                    </div>
                  </div>
                ))}
                {joinRequests.length === 0 && <EmptyState title="Нет заявок" text="Новые подключения node-agent появятся здесь." />}
              </div>
            </article>
          </section>
        )}

        {activeView === "roles" && (
          <section className="stack">
            <article className="card">
              <h3>Область ролей</h3>
              <p className="muted">Capabilities — технические факты. Роли — явные разрешения. Область организации может ограничивать сервисные роли.</p>
              <label>
                UUID организации для новых назначений ролей, опционально
                <input value={roleOrgScope} onChange={(event) => setRoleOrgScope(event.target.value)} placeholder="пусто = роль на весь кластер" />
              </label>
            </article>
            {nodes.map((node) => (
              <article className="card roleRow" key={node.id}>
                <div>
                  <h3>{node.name}</h3>
                  <p>{summarizeRoles(rolesByNode[node.id] || [])}</p>
                </div>
                <select
                  defaultValue=""
                  onChange={(event) => {
                    const role = event.target.value;
                    event.currentTarget.value = "";
                    if (role) {
                      void runAction(() => client.assignRole(selectedClusterId, node.id, role, roleOrgScope || undefined), `${role} назначена узлу ${node.name}.`);
                    }
                  }}
                >
                  <option value="">Назначить роль...</option>
                  {roleOptions.map((role) => (
                    <option key={role} value={role}>
                      {role}
                    </option>
                  ))}
                </select>
              </article>
            ))}
          </section>
        )}

        {activeView === "workloads" && (
          <section className="grid two">
            <article className="card">
              <h3>Желаемое состояние сервиса</h3>
              <p className="muted">Здесь задается только желаемое состояние. Runtime-исполнение остается под контролем node-agent и политик.</p>
              <FormGrid>
                <label>
                  Узел
                  <select value={workloadForm.nodeId} onChange={(event) => setWorkloadForm({ ...workloadForm, nodeId: event.target.value })}>
                    <option value="">Выберите узел...</option>
                    {nodes.map((node) => (
                      <option key={node.id} value={node.id}>
                        {node.name}
                      </option>
                    ))}
                  </select>
                </label>
                <label>
                  Сервис
                  <select value={workloadForm.serviceType} onChange={(event) => setWorkloadForm({ ...workloadForm, serviceType: event.target.value })}>
                    {roleOptions.map((role) => (
                      <option key={role} value={role}>
                        {role}
                      </option>
                    ))}
                  </select>
                </label>
                <label>
                  Желаемое состояние
                  <select value={workloadForm.desiredState} onChange={(event) => setWorkloadForm({ ...workloadForm, desiredState: event.target.value })}>
                    <option value="enabled">включено</option>
                    <option value="disabled">выключено</option>
                  </select>
                </label>
                <label>
                  Режим runtime
                  <select value={workloadForm.runtimeMode} onChange={(event) => setWorkloadForm({ ...workloadForm, runtimeMode: event.target.value })}>
                    <option value="container">контейнер</option>
                    <option value="native">нативно</option>
                  </select>
                </label>
                <label>
                  Версия
                  <input value={workloadForm.version} onChange={(event) => setWorkloadForm({ ...workloadForm, version: event.target.value })} />
                </label>
              </FormGrid>
              <label>
                Config JSON
                <textarea value={workloadForm.configJson} onChange={(event) => setWorkloadForm({ ...workloadForm, configJson: event.target.value })} />
              </label>
              <label>
                Environment JSON
                <textarea
                  value={workloadForm.environmentJson}
                  onChange={(event) => setWorkloadForm({ ...workloadForm, environmentJson: event.target.value })}
                />
              </label>
              <button
                className="primary"
                disabled={!workloadForm.nodeId || !selectedClusterId}
                onClick={() =>
                  void runAction(
                    () =>
                      client.setDesiredWorkload(selectedClusterId, workloadForm.nodeId, workloadForm.serviceType, {
                        desiredState: workloadForm.desiredState,
                        runtimeMode: workloadForm.runtimeMode,
                        version: workloadForm.version,
                        config: parseJSONObject(workloadForm.configJson, "config сервиса"),
                        environment: parseJSONObject(workloadForm.environmentJson, "environment сервиса"),
                      }),
                    "Желаемое состояние сервиса обновлено.",
                  )
                }
              >
                Задать желаемое состояние
              </button>
            </article>

            <article className="card">
              <h3>Отчеты сервисов</h3>
              <div className="stack">
                {nodes.map((node) => (
                  <div className="workloadBlock" key={node.id}>
                    <strong>{node.name}</strong>
                    {(workloadsByNode[node.id] || []).length === 0 ? (
                      <p className="muted">Статус пока не получен.</p>
                    ) : (
                      <DataTable
                        columns={["сервис", "состояние", "runtime", "наблюдение"]}
                        rows={(workloadsByNode[node.id] || []).map((workload) => [
                          workload.service_type,
                          workload.reported_state,
                          workload.runtime_mode,
                          formatDate(workload.observed_at),
                        ])}
                      />
                    )}
                  </div>
                ))}
              </div>
            </article>
          </section>
        )}

        {activeView === "fabric" && (
          <section className="grid two">
            <article className="card span2">
              <h3>Граница подготовки Fabric</h3>
              <p className="muted">
                Этот экран показывает synthetic/control-plane подготовку и C17Z11 boundary: production forwarding доступен только для route-bound
                `fabric.control` при явном gate. Service traffic, RDP, VPN и произвольный relay здесь не включены.
              </p>
              <div className="signalStrip">
                <Signal label="Synthetic configs" value={`${syntheticConfigEnabledCount}/${nodes.length}`} />
                <Signal label="Routes" value={String(syntheticRouteCount)} />
                <Signal label="Endpoints / candidates" value={`${syntheticPeerEndpointCount}/${syntheticCandidateCount}`} />
                <Signal label="Peer dir / seeds" value={`${syntheticPeerDirectoryCount}/${syntheticRecoverySeedCount}`} />
                <Signal label="Scoped production flag" value={productionForwardingConfigCount === 0 ? "false" : `true:${productionForwardingConfigCount}`} />
              </div>
            </article>
            <article className="card">
              <div className="cardHead">
                <div>
                  <h3>{t.fabricEntryPoints}</h3>
                  <p className="muted">{t.fabricEntryPointHelp}</p>
                </div>
                <span className="pill">{entryPoints.length}</span>
              </div>
              <FormGrid>
                <label>
                  {t.endpointName}
                  <input value={entryPointForm.name} onChange={(event) => setEntryPointForm({ ...entryPointForm, name: event.target.value })} />
                </label>
                <label>
                  {t.endpointType}
                  <select
                    value={entryPointForm.endpointType}
                    onChange={(event) => setEntryPointForm({ ...entryPointForm, endpointType: event.target.value })}
                  >
                    <option value="client_access">client_access</option>
                    <option value="admin">admin</option>
                    <option value="api">api</option>
                    <option value="other">other</option>
                  </select>
                </label>
                <label className="span2">
                  {t.publicEndpoint}
                  <input
                    placeholder="wss://entry.example.com"
                    value={entryPointForm.publicEndpoint}
                    onChange={(event) => setEntryPointForm({ ...entryPointForm, publicEndpoint: event.target.value })}
                  />
                </label>
              </FormGrid>
              <div className="actions">
                <button
                  className="primary"
                  disabled={!entryPointForm.name.trim()}
                  onClick={() =>
                    void runAction(async () => {
                      await client.createFabricEntryPoint(selectedClusterId, {
                        name: entryPointForm.name,
                        endpointType: entryPointForm.endpointType,
                        publicEndpoint: entryPointForm.publicEndpoint || null,
                      });
                      setEntryPointForm({ name: "", endpointType: "client_access", publicEndpoint: "" });
                    }, "Точка входа создана.")
                  }
                >
                  {t.createEntryPoint}
                </button>
              </div>
              <div className="stack">
                {entryPoints.map((item) => {
                  const assignedNodes = entryPointNodesById[item.id] || [];
                  return (
                    <section className="nodePanel" key={item.id}>
                      <div className="cardHead">
                        <div>
                          <h4>{item.name}</h4>
                          <p className="muted">
                            {item.endpoint_type} · {item.public_endpoint || t.addressNotSet}
                          </p>
                        </div>
                        <Status value={item.status} />
                      </div>
                      <h5>{t.endpointNodes}</h5>
                      {assignedNodes.length === 0 ? (
                        <p className="muted">{t.assignedNodesEmpty}</p>
                      ) : (
                        <div className="membershipList">
                          {assignedNodes.map((assignment) => (
                            <span className={assignment.status === "active" ? "pill good" : "pill"} key={`${item.id}-${assignment.node_id}`}>
                              {nodeName(nodes, assignment.node_id)} · {statusLabel(assignment.status)} · p{assignment.priority}
                            </span>
                          ))}
                        </div>
                      )}
                      <div className="actions">
                        <select
                          value={entryPointNodeDrafts[item.id] || ""}
                          onChange={(event) => setEntryPointNodeDrafts({ ...entryPointNodeDrafts, [item.id]: event.target.value })}
                        >
                          <option value="">{t.selectNode}</option>
                          {nodes.map((node) => (
                            <option key={node.id} value={node.id}>
                              {node.name}
                            </option>
                          ))}
                        </select>
                        <button
                          disabled={!entryPointNodeDrafts[item.id]}
                          onClick={() =>
                            void runAction(
                              () => client.setFabricEntryPointNode(selectedClusterId, item.id, entryPointNodeDrafts[item.id], { status: "active" }),
                              "Узел назначен точке входа.",
                            )
                          }
                        >
                          {t.assignEndpointNode}
                        </button>
                      </div>
                    </section>
                  );
                })}
                {entryPoints.length === 0 && <EmptyState title={t.fabricEntryPoints} text={t.entryPointsEmpty} />}
              </div>
            </article>
            <article className="card">
              <div className="cardHead">
                <div>
                  <h3>{t.fabricEgressPools}</h3>
                  <p className="muted">{t.fabricEgressPoolHelp}</p>
                </div>
                <span className="pill">{egressPools.length}</span>
              </div>
              <FormGrid>
                <label>
                  {t.endpointName}
                  <input value={egressPoolForm.name} onChange={(event) => setEgressPoolForm({ ...egressPoolForm, name: event.target.value })} />
                </label>
                <label>
                  {t.description}
                  <input
                    value={egressPoolForm.description}
                    onChange={(event) => setEgressPoolForm({ ...egressPoolForm, description: event.target.value })}
                  />
                </label>
                <label className="span2">
                  {t.routeScope}
                  <textarea
                    rows={5}
                    value={egressPoolForm.routeScope}
                    onChange={(event) => setEgressPoolForm({ ...egressPoolForm, routeScope: event.target.value })}
                  />
                </label>
              </FormGrid>
              <div className="actions">
                <button
                  className="primary"
                  disabled={!egressPoolForm.name.trim()}
                  onClick={() =>
                    void runAction(async () => {
                      const routeScope = parseJSONObject(egressPoolForm.routeScope, "Route scope JSON");
                      await client.createFabricEgressPool(selectedClusterId, {
                        name: egressPoolForm.name,
                        description: egressPoolForm.description || null,
                        routeScope,
                      });
                      setEgressPoolForm({ name: "", description: "", routeScope: "{\n  \"routes\": []\n}" });
                    }, "Выходная зона создана.")
                  }
                >
                  {t.createEgressPool}
                </button>
              </div>
              <div className="stack">
                {egressPools.map((item) => {
                  const assignedNodes = egressPoolNodesById[item.id] || [];
                  return (
                    <section className="nodePanel" key={item.id}>
                      <div className="cardHead">
                        <div>
                          <h4>{item.name}</h4>
                          <p className="muted">{item.description || t.descriptionNotSet}</p>
                        </div>
                        <Status value={item.status} />
                      </div>
                      <p className="muted">{JSON.stringify(item.route_scope || {})}</p>
                      <h5>{t.endpointNodes}</h5>
                      {assignedNodes.length === 0 ? (
                        <p className="muted">{t.assignedNodesEmpty}</p>
                      ) : (
                        <div className="membershipList">
                          {assignedNodes.map((assignment) => (
                            <span className={assignment.status === "active" ? "pill good" : "pill"} key={`${item.id}-${assignment.node_id}`}>
                              {nodeName(nodes, assignment.node_id)} · {statusLabel(assignment.status)} · p{assignment.priority}
                            </span>
                          ))}
                        </div>
                      )}
                      <div className="actions">
                        <select
                          value={egressPoolNodeDrafts[item.id] || ""}
                          onChange={(event) => setEgressPoolNodeDrafts({ ...egressPoolNodeDrafts, [item.id]: event.target.value })}
                        >
                          <option value="">{t.selectNode}</option>
                          {nodes.map((node) => (
                            <option key={node.id} value={node.id}>
                              {node.name}
                            </option>
                          ))}
                        </select>
                        <button
                          disabled={!egressPoolNodeDrafts[item.id]}
                          onClick={() =>
                            void runAction(
                              () => client.setFabricEgressPoolNode(selectedClusterId, item.id, egressPoolNodeDrafts[item.id], { status: "active" }),
                              "Узел назначен выходной зоне.",
                            )
                          }
                        >
                          {t.assignEndpointNode}
                        </button>
                      </div>
                    </section>
                  );
                })}
                {egressPools.length === 0 && <EmptyState title={t.fabricEgressPools} text={t.egressPoolsEmpty} />}
              </div>
            </article>
            <article className="card span2">
              <div className="cardHead">
                <div>
                  <h3>{t.fabricMap}</h3>
                  <p className="muted">
                    Визуальный слой показывает, какие узлы живы, какие сервисы на них назначены и какие тестовые наблюдения связей проходят между ними.
                  </p>
                </div>
                <Status value={platformTestingFlag?.synthetic_links_enabled ? "enabled" : "disabled"} />
              </div>
              <FabricTopology
                nodes={nodes}
                links={meshLinks}
                entryPoints={entryPoints}
                entryPointNodesById={entryPointNodesById}
                egressPools={egressPools}
                egressPoolNodesById={egressPoolNodesById}
                rolesByNode={rolesByNode}
                workloadsByNode={workloadsByNode}
                telemetryByNode={telemetryByNode}
                labels={t}
                emptyText={t.noLinks}
              />
            </article>
            <article className="card span2">
              <div className="cardHead">
                <div>
                  <h3>Synthetic mesh config</h3>
                  <p className="muted">
                    Node-scoped config from Control Plane. Endpoint candidates and scoring inputs are visible to the platform owner only; production
                    forwarding for service traffic must remain disabled here.
                  </p>
                </div>
                <span className={productionForwardingConfigCount === 0 ? "pill good" : "pill bad"}>
                  production_forwarding={productionForwardingConfigCount === 0 ? "false" : "true"}
                </span>
              </div>
              <DataTable
                columns={[
                  "узел",
                  "config",
                  "routes",
                  "peer endpoints",
                  "candidates",
                  "peer dir",
                  "recovery seeds",
                  "rendezvous leases",
                  "relay policy",
                  "path decisions",
                  "authority",
                  "scoped production",
                ]}
                rows={nodes.map((node) => {
                  const config = syntheticMeshConfigsByNode[node.id];
                  return [
                    node.name,
                    config ? (config.enabled ? "enabled" : "disabled") : "не загружен",
                    String(config?.routes.length ?? 0),
                    String(Object.keys(config?.peer_endpoints || {}).length),
                    String(config ? countPeerEndpointCandidates(config) : 0),
                    String(config?.peer_directory?.length ?? 0),
                    String(config?.recovery_seeds?.length ?? 0),
                    String(config?.rendezvous_leases?.length ?? 0),
                    rendezvousRelayPolicySummary(config),
                    routePathDecisionSummary(config),
                    config?.authority_required ? shortId(config.authority_signature?.key_fingerprint) : "не требуется",
                    config?.production_forwarding ? "true" : "false",
                  ];
                })}
              />
              <p className="muted">
                Health-aware scoring не выбирает service route и не открывает service-соединения. C17Z19 показывает control-plane route/path
                decisions, route generation status, synthetic route-health effective path и relay feedback scoring, но не переносит
                RDP/VPN/file/video/service payload.
              </p>
            </article>
            <article className="card span2">
              <h3>{t.servicePlacement}</h3>
              <DataTable
                columns={["узел", "здоровье", "роли", "желаемые / reported сервисы", "последний heartbeat"]}
                rows={nodes.map((node) => [
                  node.name,
                  node.health_status,
                  summarizeRoles(rolesByNode[node.id] || []),
                  summarizeWorkloads(workloadsByNode[node.id] || []),
                  formatDate((heartbeatsByNode[node.id] || [])[0]?.observed_at || node.last_seen_at),
                ])}
              />
            </article>
            <article className="card">
              <h3>{t.trafficFlow}</h3>
              <DataTable
                columns={["источник", "цель", "тип", "route/path", "статус", "задержка", "качество", "наблюдение"]}
                rows={meshLinks.map((link) => [
                  nodeName(nodes, link.source_node_id),
                  nodeName(nodes, link.target_node_id),
                  meshLinkObservationLabel(link),
                  meshLinkRoutePathSummary(link, nodes),
                  link.link_status,
                  link.latency_ms == null ? "н/д" : `${link.latency_ms} мс`,
                  link.quality_score == null ? "н/д" : `${link.quality_score}/100`,
                  formatDate(link.observed_at),
                ])}
              />
            </article>
            <article className="card">
              <h3>Политики QoS</h3>
              <DataTable
                columns={["класс", "приоритет", "надежность", "политика сброса"]}
                rows={qosPolicies.map((policy) => [
                  policy.service_class,
                  String(policy.priority),
                  policy.reliability_mode,
                  policy.drop_policy,
                ])}
              />
            </article>
          </section>
        )}

        {activeView === "vpn" && (
          <section className="grid two">
            <article className="card">
              <h3>Создать желаемое состояние VPN-подключения</h3>
              <p className="muted">Только control-plane. Здесь не выполняются TUN/TAP, маршруты, DNS, firewall, QoS или packet forwarding.</p>
              <FormGrid>
                <label>
                  ID организации
                  <input value={vpnForm.organizationId} onChange={(event) => setVPNForm({ ...vpnForm, organizationId: event.target.value })} />
                </label>
                <label>
                  Название
                  <input value={vpnForm.name} onChange={(event) => setVPNForm({ ...vpnForm, name: event.target.value })} />
                </label>
                <label>
                  Протокол
                  <select value={vpnForm.protocolFamily} onChange={(event) => setVPNForm({ ...vpnForm, protocolFamily: event.target.value })}>
                    <option value="generic">generic</option>
                    <option value="wireguard">wireguard</option>
                    <option value="ipsec">ipsec</option>
                    <option value="openvpn">openvpn</option>
                  </select>
                </label>
                <label>
                  Желаемое состояние
                  <select value={vpnForm.desiredState} onChange={(event) => setVPNForm({ ...vpnForm, desiredState: event.target.value })}>
                    <option value="disabled">выключено</option>
                    <option value="enabled">включено</option>
                  </select>
                </label>
                <label>
                  Ссылка на credential
                  <input value={vpnForm.credentialRef} onChange={(event) => setVPNForm({ ...vpnForm, credentialRef: event.target.value })} />
                </label>
              </FormGrid>
              <label>
                Целевой endpoint JSON
                <textarea value={vpnForm.targetEndpointJson} onChange={(event) => setVPNForm({ ...vpnForm, targetEndpointJson: event.target.value })} />
              </label>
              <label>
                Политика разрешенных узлов JSON
                <textarea
                  value={vpnForm.allowedNodePolicyJson}
                  onChange={(event) => setVPNForm({ ...vpnForm, allowedNodePolicyJson: event.target.value })}
                />
              </label>
              <details>
                <summary>Расширенные routing / QoS / placement JSON</summary>
                <label>
                  Использование маршрутизации JSON
                  <textarea value={vpnForm.routingUsageJson} onChange={(event) => setVPNForm({ ...vpnForm, routingUsageJson: event.target.value })} />
                </label>
                <label>
                  Политика маршрута JSON
                  <textarea value={vpnForm.routePolicyJson} onChange={(event) => setVPNForm({ ...vpnForm, routePolicyJson: event.target.value })} />
                </label>
                <label>
                  Политика QoS JSON
                  <textarea value={vpnForm.qosPolicyJson} onChange={(event) => setVPNForm({ ...vpnForm, qosPolicyJson: event.target.value })} />
                </label>
                <label>
                  Политика размещения JSON
                  <textarea value={vpnForm.placementPolicyJson} onChange={(event) => setVPNForm({ ...vpnForm, placementPolicyJson: event.target.value })} />
                </label>
              </details>
              <button
                className="primary"
                disabled={!selectedClusterId || !vpnForm.organizationId || !vpnForm.name}
                onClick={() =>
                  void runAction(
                    () =>
                      client.createVPNConnection(selectedClusterId, {
                        organizationId: vpnForm.organizationId,
                        name: vpnForm.name,
                        protocolFamily: vpnForm.protocolFamily,
                        credentialRef: vpnForm.credentialRef || null,
                        desiredState: vpnForm.desiredState,
                        targetEndpoint: parseJSONObject(vpnForm.targetEndpointJson, "target endpoint"),
                        allowedNodePolicy: parseJSONObject(vpnForm.allowedNodePolicyJson, "allowed node policy"),
                        routingUsage: parseJSONArray(vpnForm.routingUsageJson, "routing usage"),
                        routePolicy: parseJSONObject(vpnForm.routePolicyJson, "route policy"),
                        qosPolicy: parseJSONObject(vpnForm.qosPolicyJson, "qos policy"),
                        placementPolicy: parseJSONObject(vpnForm.placementPolicyJson, "placement policy"),
                      }),
                    "Желаемое состояние VPN создано.",
                  )
                }
              >
                Создать желаемое состояние VPN
              </button>
            </article>

            <article className="card">
              <div className="cardHead">
                <div>
                  <h3>VPN-подключения</h3>
                  <p className="muted">Только cluster-managed желаемое состояние. Runtime здесь намеренно не реализован.</p>
                </div>
                <button
                  onClick={() =>
                    void runAction(async () => {
                      const expired = await client.expireStaleVPNLeases(selectedClusterId);
                      setNotice(`Истекшие VPN lease: ${expired.length}.`);
                    }, "Stale VPN lease проверены.")
                  }
                >
                  Проверить stale lease
                </button>
              </div>
              <div className="stack">
                {vpnConnections.map((connection) => (
                  <div className="vpnCard" key={connection.id}>
                    <div>
                      <strong>{connection.name}</strong>
                      <p className="muted">
                        {connection.protocol_family} / {connection.mode} / организация {shortId(connection.organization_id)}
                      </p>
                      <Status value={connection.desired_state} />
                      <Status value={connection.status} />
                    </div>
                    <div className="stateList">
                      <StateLine label="Секрет" value={connection.credential_ref ? "задан" : "не задан"} />
                      <StateLine label="Активный lease" value={vpnLeases[connection.id] ? shortId(vpnLeases[connection.id]?.owner_node_id) : "нет"} />
                      <StateLine label="Обновлено" value={formatDate(connection.updated_at)} />
                    </div>
                    <div className="actions">
                      <button
                        disabled={connection.desired_state === "enabled"}
                        onClick={() =>
                          void runAction(
                            () => client.updateVPNConnectionDesiredState(selectedClusterId, connection.id, "enabled"),
                            "Желаемое состояние VPN включено.",
                          )
                        }
                      >
                        Включить
                      </button>
                      <button
                        disabled={connection.desired_state === "disabled"}
                        onClick={() =>
                          void runAction(
                            () => client.updateVPNConnectionDesiredState(selectedClusterId, connection.id, "disabled"),
                            "Желаемое состояние VPN выключено.",
                          )
                        }
                      >
                        Выключить
                      </button>
                    </div>
                  </div>
                ))}
                {vpnConnections.length === 0 && <EmptyState title="Нет желаемого состояния VPN" text="Control-plane записи C18 появятся здесь." />}
              </div>
            </article>
          </section>
        )}

        {activeView === "org-safe" && (
          <section className="card">
            <h3>Безопасная проекция организации</h3>
            <p className="muted">Это preview tenant-safe данных. Здесь нельзя показывать core mesh topology, peer cache, route cache или секреты.</p>
            <div className="inlineForm">
              <input value={organizationId} onChange={(event) => setOrganizationId(event.target.value)} placeholder="UUID организации" />
              <button
                disabled={!organizationId}
                onClick={() =>
                  void runAction(async () => {
                    setOrganizationSummary(await client.getOrganizationAdminSummary(organizationId));
                  }, "Сводка организации загружена.")
                }
              >
                Загрузить безопасную сводку
              </button>
            </div>
            {organizationSummary && (
              <div className="grid three">
                <Metric label="Ресурсы" value={organizationSummary.resource_count} tone="steel" />
                <Metric label="Активные сессии" value={organizationSummary.active_session_count} tone="green" />
                <article className="card">
                  <h4>Раскрытие topology</h4>
                  <p>{organizationSummary.topology_exposure}</p>
                </article>
                <article className="card span3">
                  <h4>Сервисные точки входа</h4>
                  <DataTable columns={["протокол", "количество"]} rows={organizationSummary.service_endpoints.map((item) => [item.protocol, String(item.count)])} />
                </article>
              </div>
            )}
          </section>
        )}

        {activeView === "audit" && (
          <section className="card">
            <h3>Аудит кластера</h3>
            <DataTable
              columns={["событие", "цель", "actor", "создано"]}
              rows={audit.map((event) => [
                event.event_type,
                `${event.target_type}${event.target_id ? `:${shortId(event.target_id)}` : ""}`,
                event.actor_user_id ? shortId(event.actor_user_id) : "system",
                formatDate(event.created_at),
              ])}
            />
          </section>
        )}
      </section>
    </main>
  );
}

function Metric({ label, value, tone }: { label: string; value: number; tone: string }) {
  return (
    <article className={`metric ${tone}`}>
      <span>{label}</span>
      <strong>{value}</strong>
    </article>
  );
}

function Signal({ label, value }: { label: string; value: string }) {
  return (
    <div className="signal">
      <span>{label}</span>
      <strong>{value}</strong>
    </div>
  );
}

function Status({ value }: { value: string }) {
  return <span className={`status ${value.replace(/_/g, "-")}`}>{statusLabel(value)}</span>;
}

function StateLine({ label, value }: { label: string; value: string }) {
  return (
    <div className="stateLine">
      <span>{label}</span>
      <strong>{value}</strong>
    </div>
  );
}

function EmptyState({ title, text }: { title: string; text: string }) {
  return (
    <article className="empty">
      <h3>{title}</h3>
      <p>{text}</p>
    </article>
  );
}

function TelemetryStrip({ items, emptyText }: { items: NodeTelemetryObservation[]; emptyText: string }) {
  if (items.length === 0) {
    return <EmptyState title={emptyText} text="Тестовая телеметрия появится здесь после отчета node-agent." />;
  }
  const ordered = [...items].reverse().slice(-24);
  const latest = items[0];
  const maxMemory = Math.max(...ordered.map((item) => item.memory_used_bytes || 0), 1);
  return (
    <div className="telemetryBox">
      <div className="signalStrip compact">
        <Signal label="Память" value={`${formatBytes(latest.memory_used_bytes)} / ${formatBytes(latest.memory_total_bytes)}`} />
        <Signal label="Процессор" value={latest.cpu_percent == null ? "н/д" : `${latest.cpu_percent.toFixed(1)}%`} />
        <Signal label="Процессы" value={latest.process_count == null ? "н/д" : String(latest.process_count)} />
        <Signal label="Обновлено" value={formatDate(latest.observed_at)} />
      </div>
      <div className="sparkline" aria-label="memory telemetry">
        {ordered.map((item) => (
          <span key={item.id} style={{ height: `${Math.max(8, Math.round(((item.memory_used_bytes || 0) / maxMemory) * 100))}%` }} />
        ))}
      </div>
    </div>
  );
}

function FabricTopology({
  nodes,
  links,
  entryPoints,
  entryPointNodesById,
  egressPools,
  egressPoolNodesById,
  rolesByNode,
  workloadsByNode,
  telemetryByNode,
  labels,
  emptyText,
}: {
  nodes: ClusterNode[];
  links: MeshLink[];
  entryPoints: FabricEntryPoint[];
  entryPointNodesById: Record<string, FabricEntryPointNode[]>;
  egressPools: FabricEgressPool[];
  egressPoolNodesById: Record<string, FabricEgressPoolNode[]>;
  rolesByNode: Record<string, RoleAssignment[]>;
  workloadsByNode: Record<string, WorkloadStatus[]>;
  telemetryByNode: Record<string, NodeTelemetryObservation[]>;
  labels: Record<string, string>;
  emptyText: string;
}) {
  if (nodes.length === 0) {
    return <EmptyState title="Нет узлов" text="Одобренные node-agent появятся на карте после первого heartbeat." />;
  }

  const latestLinks = latestLinkObservations(links);
  const nodePositions = new Map(nodes.map((node, index) => [node.id, topologyPoint(500, index, nodes.length, 125, 500)] as const));
  const entryPositions = new Map(entryPoints.map((entryPoint, index) => [entryPoint.id, topologyPoint(160, index, entryPoints.length, 145, 480)] as const));
  const egressPositions = new Map(egressPools.map((pool, index) => [pool.id, topologyPoint(840, index, egressPools.length, 145, 480)] as const));
  const activeEntryAssignments = entryPoints.flatMap((entryPoint) =>
    (entryPointNodesById[entryPoint.id] || [])
      .filter((assignment) => assignment.status !== "disabled")
      .map((assignment) => ({ entryPoint, assignment })),
  );
  const activeEgressAssignments = egressPools.flatMap((pool) =>
    (egressPoolNodesById[pool.id] || [])
      .filter((assignment) => assignment.status !== "disabled")
      .map((assignment) => ({ pool, assignment })),
  );
  const placementCount = activeEntryAssignments.length + activeEgressAssignments.length;

  return (
    <div className="topologyShell">
      <svg className="topologySvg" viewBox="0 0 1000 640" role="img" aria-label="Карта трафика узлов Fabric">
        <defs>
          <marker id="arrow" markerHeight="8" markerWidth="8" orient="auto" refX="7" refY="4">
            <path d="M0,0 L8,4 L0,8 Z" fill="currentColor" />
          </marker>
        </defs>
        <rect x="36" y="58" width="248" height="522" rx="30" className="topologyZone ingress" />
        <rect x="322" y="58" width="356" height="522" rx="30" className="topologyZone core" />
        <rect x="716" y="58" width="248" height="522" rx="30" className="topologyZone egress" />
        <text x="160" y="98" className="topologyLayerLabel">
          {labels.fabricIngressLayer}
        </text>
        <text x="500" y="98" className="topologyLayerLabel">
          {labels.fabricNodeLayer}
        </text>
        <text x="840" y="98" className="topologyLayerLabel">
          {labels.fabricEgressLayer}
        </text>

        {activeEntryAssignments.map(({ entryPoint, assignment }) => {
          const source = entryPositions.get(entryPoint.id);
          const target = nodePositions.get(assignment.node_id);
          if (!source || !target) {
            return null;
          }
          return (
            <line
              key={`entry-${entryPoint.id}-${assignment.node_id}`}
              x1={source.x + 78}
              y1={source.y}
              x2={target.x - 62}
              y2={target.y}
              className={`topologyPlacementLink ${assignment.status === "active" ? "good" : "weak"}`}
              markerEnd="url(#arrow)"
            />
          );
        })}

        {activeEgressAssignments.map(({ pool, assignment }) => {
          const source = nodePositions.get(assignment.node_id);
          const target = egressPositions.get(pool.id);
          if (!source || !target) {
            return null;
          }
          return (
            <line
              key={`egress-${pool.id}-${assignment.node_id}`}
              x1={source.x + 62}
              y1={source.y}
              x2={target.x - 78}
              y2={target.y}
              className={`topologyPlacementLink ${assignment.status === "active" ? "good" : "weak"}`}
              markerEnd="url(#arrow)"
            />
          );
        })}

        {latestLinks.map((link) => {
          const source = nodePositions.get(link.source_node_id);
          const target = nodePositions.get(link.target_node_id);
          if (!source || !target) {
            return null;
          }
          const midX = (source.x + target.x) / 2;
          const midY = (source.y + target.y) / 2;
          return (
            <g key={link.id || `${link.source_node_id}-${link.target_node_id}`}>
              <line
                x1={source.x}
                y1={source.y}
                x2={target.x}
                y2={target.y}
                className={`topologyLink ${linkTone(link)}`}
                markerEnd="url(#arrow)"
              />
              <text x={midX} y={midY - 8} className="topologyLinkLabel">
                {meshLinkTopologyLabel(link)}
              </text>
            </g>
          );
        })}
        {entryPoints.map((entryPoint) => {
          const point = entryPositions.get(entryPoint.id)!;
          const count = (entryPointNodesById[entryPoint.id] || []).length;
          return (
            <g key={entryPoint.id} className="topologyEndpoint">
              <rect x={point.x - 86} y={point.y - 36} width="172" height="72" rx="20" className={`topologyEndpointRect ${entryPoint.status}`} />
              <text x={point.x} y={point.y - 8} className="topologyEndpointName">
                {trimNodeName(entryPoint.name)}
              </text>
              <text x={point.x} y={point.y + 15} className="topologyEndpointMeta">
                {entryPoint.endpoint_type} · {count}
              </text>
            </g>
          );
        })}
        {nodes.map((node) => {
          const point = nodePositions.get(node.id)!;
          const latestTelemetry = (telemetryByNode[node.id] || [])[0];
          return (
            <g key={node.id} className="topologyNode">
              <circle cx={point.x} cy={point.y} r="54" className={`topologyNodeCircle ${node.health_status}`} />
              <text x={point.x} y={point.y - 12} className="topologyNodeName">
                {trimNodeName(node.name)}
              </text>
              <text x={point.x} y={point.y + 10} className="topologyNodeMeta">
                {(rolesByNode[node.id] || []).length} ролей / {(workloadsByNode[node.id] || []).length} серв.
              </text>
              <text x={point.x} y={point.y + 31} className="topologyNodeMeta">
                {formatBytes(latestTelemetry?.memory_used_bytes)}
              </text>
            </g>
          );
        })}
        {egressPools.map((pool) => {
          const point = egressPositions.get(pool.id)!;
          const count = (egressPoolNodesById[pool.id] || []).length;
          return (
            <g key={pool.id} className="topologyEndpoint">
              <rect x={point.x - 86} y={point.y - 36} width="172" height="72" rx="20" className={`topologyEndpointRect ${pool.status}`} />
              <text x={point.x} y={point.y - 8} className="topologyEndpointName">
                {trimNodeName(pool.name)}
              </text>
              <text x={point.x} y={point.y + 15} className="topologyEndpointMeta">
                egress · {count}
              </text>
            </g>
          );
        })}
        {latestLinks.length === 0 && placementCount === 0 && (
          <text x="500" y="606" className="topologyEmpty">
            {emptyText}
          </text>
        )}
      </svg>
      <div className="topologyLegend">
        <span>
          <i className="legendLine placement" /> {labels.placementIntent}: {placementCount}
        </span>
        <span>
          <i className="legendLine observed" /> {labels.observedPeerLinks}: {latestLinks.length}
        </span>
      </div>
      <div className="serviceTags">
        {entryPoints.map((entryPoint) => (
          <div className="serviceTag" key={entryPoint.id}>
            <strong>{entryPoint.name}</strong>
            <span>{entryPoint.endpoint_type}</span>
            <small>{(entryPointNodesById[entryPoint.id] || []).map((item) => nodeName(nodes, item.node_id)).join(", ") || labels.assignedNodesEmpty}</small>
          </div>
        ))}
        {nodes.map((node) => (
          <div className="serviceTag" key={node.id}>
            <strong>{node.name}</strong>
            <span>{node.health_status}</span>
            <small>{summarizeWorkloads(workloadsByNode[node.id] || [])}</small>
          </div>
        ))}
        {egressPools.map((pool) => (
          <div className="serviceTag" key={pool.id}>
            <strong>{pool.name}</strong>
            <span>{pool.status}</span>
            <small>{(egressPoolNodesById[pool.id] || []).map((item) => nodeName(nodes, item.node_id)).join(", ") || labels.assignedNodesEmpty}</small>
          </div>
        ))}
      </div>
    </div>
  );
}

function topologyPoint(x: number, index: number, count: number, top: number, bottom: number) {
  if (count <= 1) {
    return { x, y: Math.round((top + bottom) / 2) };
  }
  return { x, y: Math.round(top + ((bottom - top) * index) / (count - 1)) };
}

function NodeGroupTree({ groups, nodes, labels }: { groups: ClusterNodeGroup[]; nodes: ClusterNode[]; labels: Record<string, string> }) {
  const rootGroups = groups
    .filter((group) => !group.parent_group_id)
    .sort((left, right) => left.sort_order - right.sort_order || left.name.localeCompare(right.name));
  const ungroupedNodes = nodes.filter((node) => !node.node_group_id);

  if (groups.length === 0 && nodes.length === 0) {
    return <EmptyState title="Нет узлов" text="Одобренные node-agent появятся здесь." />;
  }

  return (
    <div className="treeList">
      {rootGroups.map((group) => (
        <NodeGroupBranch key={group.id} group={group} groups={groups} nodes={nodes} depth={0} />
      ))}
      {ungroupedNodes.length > 0 && (
        <section className="treeBranch">
          <h4>{labels.ungroupedNodes}</h4>
          <div className="treeNodeList">
            {ungroupedNodes.map((node) => (
              <span className="pill" key={node.id}>
                {node.name}
              </span>
            ))}
          </div>
        </section>
      )}
    </div>
  );
}

function NodeGroupBranch({ group, groups, nodes, depth }: { group: ClusterNodeGroup; groups: ClusterNodeGroup[]; nodes: ClusterNode[]; depth: number }) {
  const childGroups = groups
    .filter((item) => item.parent_group_id === group.id)
    .sort((left, right) => left.sort_order - right.sort_order || left.name.localeCompare(right.name));
  const groupedNodes = nodes.filter((node) => node.node_group_id === group.id);

  return (
    <section className="treeBranch" style={{ marginLeft: `${depth * 18}px` }}>
      <h4>
        {group.name}
        <span className="pill">{groupedNodes.length}</span>
      </h4>
      {group.description && <p className="muted">{group.description}</p>}
      <div className="treeNodeList">
        {groupedNodes.map((node) => (
          <span className="pill good" key={node.id}>
            {node.name}
          </span>
        ))}
      </div>
      {childGroups.map((child) => (
        <NodeGroupBranch key={child.id} group={child} groups={groups} nodes={nodes} depth={depth + 1} />
      ))}
    </section>
  );
}

function FormGrid({ children }: { children: ReactNode }) {
  return <div className="formGrid">{children}</div>;
}

function DataTable({ columns, rows }: { columns: string[]; rows: ReactNode[][] }) {
  if (rows.length === 0) {
    return <EmptyState title="Нет данных" text="В текущей области пока нечего показать." />;
  }
  return (
    <div className="tableWrap">
      <table>
        <thead>
          <tr>
            {columns.map((column) => (
              <th key={column}>{column}</th>
            ))}
          </tr>
        </thead>
        <tbody>
          {rows.map((row, index) => (
            <tr key={index}>
              {row.map((cell, cellIndex) => (
                <td key={`${index}-${cellIndex}`}>{cell}</td>
              ))}
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}

function parseJSONObject(raw: string, label: string): Record<string, unknown> {
  const parsed = JSON.parse(raw || "{}") as unknown;
  if (!parsed || Array.isArray(parsed) || typeof parsed !== "object") {
    throw new Error(`${label}: требуется JSON object.`);
  }
  return parsed as Record<string, unknown>;
}

function parseJSONArray(raw: string, label: string): unknown[] {
  const parsed = JSON.parse(raw || "[]") as unknown;
  if (!Array.isArray(parsed)) {
    throw new Error(`${label}: требуется JSON array.`);
  }
  return parsed;
}

function summarizeRoles(roles: RoleAssignment[]) {
  if (roles.length === 0) {
    return "активные роли не назначены";
  }
  return roles.map((role) => `${role.role}${role.organization_id ? ` @ ${shortId(role.organization_id)}` : ""}`).join(", ");
}

function summarizeWorkloads(workloads: WorkloadStatus[]) {
  if (workloads.length === 0) {
    return "нет сервисов";
  }
  return workloads.map((workload) => `${workload.service_type}:${workload.reported_state}`).join(", ");
}

function latestLinkObservations(links: MeshLink[]) {
  const byPair = new Map<string, MeshLink>();
  for (const link of links) {
    const key = `${link.source_node_id}->${link.target_node_id}:${meshLinkObservationKey(link)}`;
    const existing = byPair.get(key);
    if (!existing || new Date(link.observed_at).getTime() > new Date(existing.observed_at).getTime()) {
      byPair.set(key, link);
    }
  }
  return [...byPair.values()];
}

function meshLinkObservationKey(link: MeshLink) {
  const observationType = meshLinkMetadataString(link, "observation_type") || "default";
  if (observationType === "synthetic_route_health") {
    return `${observationType}:${meshLinkMetadataString(link, "route_id") || link.id}`;
  }
  if (observationType === "peer_connection_manager") {
    return `${observationType}:${meshLinkMetadataString(link, "transport_mode")}:${meshLinkMetadataString(link, "relay_node_id")}`;
  }
  return observationType;
}

function meshLinkObservationLabel(link: MeshLink) {
  const observationType = meshLinkMetadataString(link, "observation_type");
  if (observationType === "synthetic_route_health") {
    const drift = link.metadata?.route_path_drift_detected === true ? "drift" : "ok";
    const applied = link.metadata?.route_path_decision_applied === true ? "decision" : "route";
    return `route-health ${applied} ${drift}`;
  }
  if (observationType === "peer_connection_manager") {
    const mode = meshLinkMetadataString(link, "transport_mode") || "manager";
    const state = meshLinkMetadataString(link, "connection_state");
    return state ? `${mode} ${state}` : mode;
  }
  return observationType || "link";
}

function meshLinkRoutePathSummary(link: MeshLink, nodes: ClusterNode[]) {
  const routeID = meshLinkMetadataString(link, "route_id");
  const relayID = meshLinkMetadataString(link, "route_path_decision_selected_relay_id") || meshLinkMetadataString(link, "relay_node_id");
  const hops = meshLinkMetadataStringArray(link, "expected_effective_hops");
  const observed = meshLinkMetadataStringArray(link, "observed_ack_path");
  const path = hops.length > 0 ? hops : observed;
  const parts: string[] = [];
  if (routeID) {
    parts.push(shortId(routeID));
  }
  if (relayID) {
    parts.push(`via ${shortId(relayID)}`);
  }
  if (path.length > 0) {
    parts.push(path.map((id) => trimNodeName(nodeName(nodes, id))).join(" > "));
  }
  return parts.length > 0 ? parts.join(" / ") : "н/д";
}

function meshLinkTopologyLabel(link: MeshLink) {
  if (meshLinkMetadataString(link, "observation_type") === "synthetic_route_health") {
    return link.metadata?.route_path_drift_detected === true ? "drift" : "route";
  }
  return link.latency_ms == null ? "связь" : `${link.latency_ms}мс`;
}

function meshLinkMetadataString(link: MeshLink, key: string) {
  const value = link.metadata?.[key];
  return typeof value === "string" ? value : "";
}

function meshLinkMetadataStringArray(link: MeshLink, key: string) {
  const value = link.metadata?.[key];
  return Array.isArray(value) ? value.filter((item): item is string => typeof item === "string") : [];
}

function countPeerEndpointCandidates(config: NodeSyntheticMeshConfig) {
  return Object.values(config.peer_endpoint_candidates || {}).reduce((sum, candidates) => sum + candidates.length, 0);
}

function rendezvousRelayPolicySummary(config?: NodeSyntheticMeshConfig) {
  const policy = config?.rendezvous_relay_policy;
  if (!policy) {
    return "none";
  }
  const parts = [`stale${policy.stale_relay_count}`, `wd${policy.withdrawn_lease_count}`, `repl${policy.replacement_lease_count}`];
  if (policy.scoring_mode.includes("synthetic_route_health_feedback")) {
    parts.push("rh feedback");
  }
  const selected = policy.decisions?.find((decision) => decision.selected_relay_id);
  if (selected?.selected_relay_id) {
    parts.push(`via ${shortId(selected.selected_relay_id)}`);
  }
  return parts.join(" ");
}

function routePathDecisionSummary(config?: NodeSyntheticMeshConfig) {
  const report = config?.route_path_decisions;
  if (!report) {
    return "none";
  }
  const parts = [`path${report.decision_count}`, `repl${report.replacement_decision_count}`];
  const selected = report.decisions?.find((decision) => decision.selected_relay_id || decision.next_hop_id);
  if (selected?.selected_relay_id) {
    parts.push(`via ${shortId(selected.selected_relay_id)}`);
  } else if (selected?.next_hop_id) {
    parts.push(`next ${shortId(selected.next_hop_id)}`);
  }
  return parts.join(" ");
}

function nodeName(nodes: ClusterNode[], id: string) {
  return nodes.find((node) => node.id === id)?.name || shortId(id);
}

function groupPathLabel(group: ClusterNodeGroup, groups: ClusterNodeGroup[]) {
  const byId = new Map(groups.map((item) => [item.id, item]));
  const parts = [group.name];
  let parentID = group.parent_group_id;
  const seen = new Set<string>([group.id]);
  while (parentID && !seen.has(parentID)) {
    seen.add(parentID);
    const parent = byId.get(parentID);
    if (!parent) {
      break;
    }
    parts.unshift(parent.name);
    parentID = parent.parent_group_id;
  }
  return parts.join(" / ");
}

function groupPathLabelById(groupId: string, groups: ClusterNodeGroup[]) {
  const group = groups.find((item) => item.id === groupId);
  return group ? groupPathLabel(group, groups) : groupId;
}

function descendantGroupIds(groupId: string, groups: ClusterNodeGroup[]) {
  const result: string[] = [];
  const childrenByParent = new Map<string, ClusterNodeGroup[]>();
  for (const group of groups) {
    const parentKey = group.parent_group_id || "";
    childrenByParent.set(parentKey, [...(childrenByParent.get(parentKey) || []), group]);
  }
  const visit = (parentId: string) => {
    for (const child of childrenByParent.get(parentId) || []) {
      result.push(child.id);
      visit(child.id);
    }
  };
  visit(groupId);
  return result;
}

function buildNodeInventoryTreeRows(
  entries: NodeInventoryEntry[],
  groups: ClusterNodeGroup[],
  selectedClusterId: string,
  labels: Record<string, string>,
  collapsedGroupKeys: Set<string>,
): NodeInventoryTreeRow[] {
  const rows: NodeInventoryTreeRow[] = [];
  const entriesByGroup = new Map<string, NodeInventoryEntry[]>();
  const activeUngrouped: NodeInventoryEntry[] = [];
  const outsideActiveCluster: NodeInventoryEntry[] = [];

  for (const entry of entries) {
    const activeMembership = entry.memberships.find((membership) => membership.cluster.id === selectedClusterId);
    if (!activeMembership) {
      outsideActiveCluster.push(entry);
      continue;
    }
    const groupID = activeMembership.node.node_group_id;
    if (!groupID) {
      activeUngrouped.push(entry);
      continue;
    }
    entriesByGroup.set(groupID, [...(entriesByGroup.get(groupID) || []), entry]);
  }

  const childrenByParent = new Map<string, ClusterNodeGroup[]>();
  for (const group of groups) {
    const parentKey = group.parent_group_id || "";
    childrenByParent.set(parentKey, [...(childrenByParent.get(parentKey) || []), group]);
  }
  for (const childGroups of childrenByParent.values()) {
    childGroups.sort((left, right) => left.sort_order - right.sort_order || left.name.localeCompare(right.name));
  }

  const countByGroup = new Map<string, number>();
  const countGroupEntries = (group: ClusterNodeGroup): number => {
    const cached = countByGroup.get(group.id);
    if (cached != null) {
      return cached;
    }
    let count = entriesByGroup.get(group.id)?.length || 0;
    for (const child of childrenByParent.get(group.id) || []) {
      count += countGroupEntries(child);
    }
    countByGroup.set(group.id, count);
    return count;
  };

  const appendGroup = (group: ClusterNodeGroup, depth: number): number => {
    const ownEntries = [...(entriesByGroup.get(group.id) || [])].sort((left, right) => left.node.name.localeCompare(right.node.name));
    const childGroups = childrenByParent.get(group.id) || [];
    const rowKey = `group-${group.id}`;
    const count = countGroupEntries(group);
    rows.push({ kind: "group", key: rowKey, label: group.name, depth, count, groupId: group.id });
    if (!collapsedGroupKeys.has(rowKey)) {
      for (const entry of ownEntries) {
        rows.push({ kind: "node", key: `node-${group.id}-${entry.node.id}`, entry, depth: depth + 1 });
      }
      for (const child of childGroups) {
        appendGroup(child, depth + 1);
      }
    }
    return count;
  };

  for (const group of childrenByParent.get("") || []) {
    appendGroup(group, 0);
  }

  if (activeUngrouped.length > 0) {
    const rowKey = "group-ungrouped";
    rows.push({ kind: "group", key: rowKey, label: labels.ungroupedNodes, depth: 0, count: activeUngrouped.length });
    if (!collapsedGroupKeys.has(rowKey)) {
      for (const entry of activeUngrouped.sort((left, right) => left.node.name.localeCompare(right.node.name))) {
        rows.push({ kind: "node", key: `node-ungrouped-${entry.node.id}`, entry, depth: 1 });
      }
    }
  }

  if (outsideActiveCluster.length > 0) {
    const rowKey = "group-outside-active-cluster";
    rows.push({
      kind: "group",
      key: rowKey,
      label: labels.notMemberOfActiveCluster,
      depth: 0,
      count: outsideActiveCluster.length,
    });
    if (!collapsedGroupKeys.has(rowKey)) {
      for (const entry of outsideActiveCluster.sort((left, right) => left.node.name.localeCompare(right.node.name))) {
        rows.push({ kind: "node", key: `node-outside-${entry.node.id}`, entry, depth: 1 });
      }
    }
  }

  return rows;
}

function nodesWithRole(role: string, rolesByNode: Record<string, RoleAssignment[]>) {
  return Object.entries(rolesByNode)
    .filter(([, roles]) => roles.some((assignment) => assignment.role === role && assignment.status === "active"))
    .map(([nodeId]) => nodeId);
}

function buildJoinTokenScope(input: { roles: string[]; ownershipType: string; purpose: string }): Record<string, unknown> {
  return {
    roles: input.roles,
    ownership_type: input.ownershipType,
    purpose: input.purpose.trim() || null,
    approval: {
      mode: "manual",
      auto_approve: false,
      role_assignment: "manual_after_approval",
    },
    source: "platform_owner_console",
  };
}

function toggleArrayValue(values: string[], value: string) {
  return values.includes(value) ? values.filter((item) => item !== value) : [...values, value];
}

function groupNodeInventory(
  entries: NodeInventoryEntry[],
  selectedClusterId: string,
  search: string,
  groupBy: "membership" | "health" | "ownership" | "cluster_count",
  language: Language,
) {
  const normalizedSearch = search.trim().toLowerCase();
  const groups = new Map<string, NodeInventoryEntry[]>();

  for (const entry of entries) {
    if (normalizedSearch && !nodeInventoryMatches(entry, normalizedSearch)) {
      continue;
    }
    const key = nodeInventoryGroupLabel(entry, selectedClusterId, groupBy, language);
    groups.set(key, [...(groups.get(key) || []), entry]);
  }

  return Array.from(groups.entries())
    .map(([label, items]) => ({ label, items: items.sort((left, right) => left.node.name.localeCompare(right.node.name)) }))
    .sort((left, right) => left.label.localeCompare(right.label));
}

function nodeInventoryMatches(entry: NodeInventoryEntry, search: string) {
  const values = [
    entry.node.name,
    entry.node.node_key,
    entry.node.health_status,
    entry.node.ownership_type,
    entry.node.reported_version || "",
    ...entry.memberships.flatMap((membership) => [membership.cluster.name, membership.cluster.slug, membership.node.membership_status]),
  ];
  return values.some((value) => value.toLowerCase().includes(search));
}

function nodeInventoryGroupLabel(
  entry: NodeInventoryEntry,
  selectedClusterId: string,
  groupBy: "membership" | "health" | "ownership" | "cluster_count",
  language: Language,
) {
  if (groupBy === "health") {
    return statusLabel(entry.node.health_status);
  }
  if (groupBy === "ownership") {
    return statusLabel(entry.node.ownership_type);
  }
  if (groupBy === "cluster_count") {
    return clusterCountLabel(entry.memberships.length, language);
  }

  const activeMembership = entry.memberships.find((membership) => membership.cluster.id === selectedClusterId);
  if (!activeMembership) {
    return language === "en" ? "Not in active cluster" : "Не в активном кластере";
  }
  if (activeMembership.node.membership_status === "active") {
    return language === "en" ? "In active cluster" : "В активном кластере";
  }
  return `${language === "en" ? "Membership" : "Участие"}: ${statusLabel(activeMembership.node.membership_status)}`;
}

function capabilityState(role: string, heartbeat?: NodeHeartbeat) {
  const expectedKeys = capabilityKeysByRole[role] || [];
  if (expectedKeys.length === 0 || !heartbeat) {
    return "unknown";
  }
  const capabilities = heartbeat.capabilities || {};
  return expectedKeys.some((key) => Boolean(capabilities[key])) ? "confirmed" : "missing";
}

function capabilityPillTone(role: string, heartbeat?: NodeHeartbeat) {
  const state = capabilityState(role, heartbeat);
  if (state === "confirmed") {
    return "good";
  }
  if (state === "missing") {
    return "bad";
  }
  return "";
}

function capabilityLabel(role: string, heartbeat: NodeHeartbeat | undefined, labels: Record<string, string>) {
  const state = capabilityState(role, heartbeat);
  if (state === "confirmed") {
    return labels.capabilityConfirmed;
  }
  if (state === "missing") {
    return labels.capabilityMissing;
  }
  return labels.capabilityUnknown;
}

function capabilityOptionLabel(role: string, heartbeat: NodeHeartbeat | undefined, language: Language) {
  const state = capabilityState(role, heartbeat);
  if (language === "en") {
    return state === "confirmed" ? "capable" : state === "missing" ? "not reported" : "unknown";
  }
  return state === "confirmed" ? "подходит" : state === "missing" ? "не заявлено" : "неизвестно";
}

function meshRecoverySummary(heartbeat?: NodeHeartbeat) {
  const report = heartbeat?.metadata?.mesh_peer_recovery_report;
  if (!report || typeof report !== "object" || Array.isArray(report)) {
    return "н/д";
  }
  const fields = report as Record<string, unknown>;
  const mode = typeof fields.mode === "string" ? fields.mode : "unknown";
  const ready = typeof fields.ready_peer_count === "number" ? fields.ready_peer_count : null;
  const target = typeof fields.target_ready_peers === "number" ? fields.target_ready_peers : null;
  const deficit = typeof fields.deficit === "number" ? fields.deficit : 0;
  const base = ready == null || target == null ? mode : `${mode} ${ready}/${target}`;
  return deficit > 0 ? `${base} deficit ${deficit}` : base;
}

function meshConnectionIntentSummary(heartbeat?: NodeHeartbeat) {
  const report = heartbeat?.metadata?.mesh_peer_connection_intent_report;
  if (!report || typeof report !== "object" || Array.isArray(report)) {
    return meshConnectionManagerSummary(heartbeat);
  }
  const fields = report as Record<string, unknown>;
  const intentCount = typeof fields.intent_count === "number" ? fields.intent_count : 0;
  const maintain = typeof fields.maintain_count === "number" ? fields.maintain_count : 0;
  const recover = typeof fields.recover_count === "number" ? fields.recover_count : 0;
  const rendezvous = typeof fields.rendezvous_required_count === "number" ? fields.rendezvous_required_count : 0;
  const resolved = typeof fields.rendezvous_resolved_count === "number" ? fields.rendezvous_resolved_count : 0;
  const relayControl = typeof fields.relay_control_count === "number" ? fields.relay_control_count : 0;
  const rvPart = [`rv${rendezvous}`];
  if (resolved > 0) {
    rvPart.push(`ok${resolved}`);
  }
  if (relayControl > 0) {
    rvPart.push(`relay${relayControl}`);
  }
  const base =
    rendezvous > 0 || resolved > 0 || relayControl > 0
      ? `${intentCount} intents m${maintain}/r${recover} ${rvPart.join("/")}`
      : `${intentCount} intents m${maintain}/r${recover}`;
  const manager = meshConnectionManagerSummary(heartbeat);
  return manager === "н/д" ? base : `${base}; ${manager}`;
}

function meshRendezvousLeaseSummary(heartbeat?: NodeHeartbeat) {
  const report = heartbeat?.metadata?.mesh_rendezvous_lease_report;
  if (!report || typeof report !== "object" || Array.isArray(report)) {
    return "н/д";
  }
  const fields = report as Record<string, unknown>;
  const total = typeof fields.lease_count === "number" ? fields.lease_count : 0;
  const active = typeof fields.active_count === "number" ? fields.active_count : 0;
  const relay = typeof fields.admitted_as_relay_count === "number" ? fields.admitted_as_relay_count : 0;
  const peer = typeof fields.admitted_as_peer_count === "number" ? fields.admitted_as_peer_count : 0;
  const renewal = typeof fields.renewal_needed_count === "number" ? fields.renewal_needed_count : 0;
  const ready = typeof fields.relay_control_ready_count === "number" ? fields.relay_control_ready_count : 0;
  const stale = typeof fields.stale_relay_count === "number" ? fields.stale_relay_count : 0;
  const refreshAttempts = typeof fields.refresh_attempt_count === "number" ? fields.refresh_attempt_count : 0;
  const refreshSuccess = typeof fields.refresh_success_count === "number" ? fields.refresh_success_count : 0;
  const parts = [`lease ${active}/${total}`];
  if (relay > 0) {
    parts.push(`relay${relay}`);
  }
  if (peer > 0) {
    parts.push(`peer${peer}`);
  }
  if (renewal > 0) {
    parts.push(`renew${renewal}`);
  }
  if (stale > 0) {
    parts.push(`stale${stale}`);
  }
  if (ready > 0) {
    parts.push(`ready${ready}`);
  }
  if (refreshAttempts > 0) {
    parts.push(`ref${refreshSuccess}/${refreshAttempts}`);
  }
  return parts.join(" ");
}

function meshRoutePathDecisionSummary(heartbeat?: NodeHeartbeat) {
  const report = heartbeat?.metadata?.mesh_route_path_decision_report;
  if (!report || typeof report !== "object" || Array.isArray(report)) {
    return "н/д";
  }
  const fields = report as Record<string, unknown>;
  const total = typeof fields.decision_count === "number" ? fields.decision_count : 0;
  const replacements = typeof fields.replacement_decision_count === "number" ? fields.replacement_decision_count : 0;
  const local = typeof fields.local_effective_path_count === "number" ? fields.local_effective_path_count : 0;
  const next = typeof fields.next_hop_available_count === "number" ? fields.next_hop_available_count : 0;
  const withdrawn = typeof fields.withdrawn_local_relay_count === "number" ? fields.withdrawn_local_relay_count : 0;
  const parts = [`path ${local}/${total}`];
  if (replacements > 0) {
    parts.push(`repl${replacements}`);
  }
  if (next > 0) {
    parts.push(`next${next}`);
  }
  if (withdrawn > 0) {
    parts.push(`wd${withdrawn}`);
  }
  return parts.join(" ");
}

function meshRouteGenerationSummary(heartbeat?: NodeHeartbeat) {
  const report = heartbeat?.metadata?.mesh_route_generation_report;
  if (!report || typeof report !== "object" || Array.isArray(report)) {
    return "н/д";
  }
  const fields = report as Record<string, unknown>;
  const active = typeof fields.active_decision_count === "number" ? fields.active_decision_count : 0;
  const applied = typeof fields.applied_decision_count === "number" ? fields.applied_decision_count : 0;
  const withdrawn = typeof fields.withdrawn_decision_count === "number" ? fields.withdrawn_decision_count : 0;
  const changed = fields.generation_changed === true;
  const parts = [`gen ${active}`];
  if (applied > 0) {
    parts.push(`ap${applied}`);
  }
  if (withdrawn > 0) {
    parts.push(`wd${withdrawn}`);
  }
  if (changed) {
    parts.push("chg");
  }
  return parts.join(" ");
}

function meshRouteHealthConfigSummary(heartbeat?: NodeHeartbeat) {
  const report = heartbeat?.metadata?.mesh_route_health_config_report;
  if (!report || typeof report !== "object" || Array.isArray(report)) {
    return "н/д";
  }
  const fields = report as Record<string, unknown>;
  const feedbackReport = heartbeat?.metadata?.mesh_route_health_feedback_refresh_report;
  const feedbackFields =
    feedbackReport && typeof feedbackReport === "object" && !Array.isArray(feedbackReport)
      ? (feedbackReport as Record<string, unknown>)
      : {};
  const routes = typeof fields.route_health_route_count === "number" ? fields.route_health_route_count : 0;
  const applied = typeof fields.route_path_decision_applied_count === "number" ? fields.route_path_decision_applied_count : 0;
  const replacements = typeof fields.replacement_route_health_route_count === "number" ? fields.replacement_route_health_route_count : 0;
  const drift = typeof fields.route_health_decision_drift_candidate_count === "number" ? fields.route_health_decision_drift_candidate_count : 0;
  const feedbackAttempts =
    typeof feedbackFields.feedback_refresh_attempt_count === "number"
      ? feedbackFields.feedback_refresh_attempt_count
      : typeof fields.feedback_refresh_attempt_count === "number"
        ? fields.feedback_refresh_attempt_count
        : 0;
  const feedbackSuccesses =
    typeof feedbackFields.feedback_refresh_success_count === "number"
      ? feedbackFields.feedback_refresh_success_count
      : typeof fields.feedback_refresh_success_count === "number"
        ? fields.feedback_refresh_success_count
        : 0;
  const feedbackSuppressed =
    typeof feedbackFields.feedback_refresh_suppressed_count === "number"
      ? feedbackFields.feedback_refresh_suppressed_count
      : typeof fields.feedback_refresh_suppressed_count === "number"
        ? fields.feedback_refresh_suppressed_count
        : 0;
  const parts = [`rh ${applied}/${routes}`];
  if (replacements > 0) {
    parts.push(`repl${replacements}`);
  }
  if (drift > 0) {
    parts.push(`drift${drift}`);
  }
  if (feedbackAttempts > 0 || feedbackSuppressed > 0) {
    parts.push(`fb${feedbackSuccesses}/${feedbackAttempts}`);
  }
  if (feedbackSuppressed > 0) {
    parts.push(`sup${feedbackSuppressed}`);
  }
  return parts.join(" ");
}

function meshConnectionManagerSummary(heartbeat?: NodeHeartbeat) {
  const report = heartbeat?.metadata?.mesh_peer_connection_manager_report;
  if (!report || typeof report !== "object" || Array.isArray(report)) {
    return "н/д";
  }
  const fields = report as Record<string, unknown>;
  if (fields.enabled === false) {
    return "manager off";
  }
  const attempted = typeof fields.attempted === "number" ? fields.attempted : 0;
  const succeeded = typeof fields.succeeded === "number" ? fields.succeeded : 0;
  const deferred = typeof fields.deferred === "number" ? fields.deferred : 0;
  const relayControl = typeof fields.relay_control_count === "number" ? fields.relay_control_count : 0;
  const base = relayControl > 0 ? `mgr ${succeeded}/${attempted} relay${relayControl}` : `mgr ${succeeded}/${attempted}`;
  return deferred > 0 ? `${base} def${deferred}` : base;
}

function clusterCountLabel(count: number, language: Language) {
  if (language === "en") {
    return count === 1 ? "1 cluster" : `${count} clusters`;
  }
  const mod10 = count % 10;
  const mod100 = count % 100;
  if (mod10 === 1 && mod100 !== 11) {
    return `${count} кластер`;
  }
  if (mod10 >= 2 && mod10 <= 4 && (mod100 < 12 || mod100 > 14)) {
    return `${count} кластера`;
  }
  return `${count} кластеров`;
}

function linkTone(link: MeshLink) {
  if (link.link_status !== "reachable") {
    return "bad";
  }
  if (link.quality_score != null && link.quality_score < 70) {
    return "weak";
  }
  if (link.latency_ms != null && link.latency_ms > 80) {
    return "weak";
  }
  return "good";
}

function trimNodeName(value: string) {
  return value.length > 16 ? `${value.slice(0, 14)}…` : value;
}

function confirmHighRisk(action: string) {
  return window.confirm(`${action}?\n\nЭто высокорисковая операция владельца платформы. Действие будет записано в аудит.`);
}

function shortId(value?: string | null) {
  if (!value) {
    return "нет";
  }
  return value.length > 12 ? `${value.slice(0, 8)}...${value.slice(-4)}` : value;
}

function formatDate(value?: string | null) {
  if (!value) {
    return "никогда";
  }
  return new Intl.DateTimeFormat(undefined, {
    dateStyle: "medium",
    timeStyle: "short",
  }).format(new Date(value));
}

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

function statusLabel(value: string) {
  const labels: Record<string, string> = {
    active: "активно",
    approved: "одобрено",
    authoritative: "authoritative",
    connecting: "подключается",
    critical: "критично",
    degraded: "degraded",
    disabled: "выключено",
    enabled: "включено",
    failed: "ошибка",
    healthy: "здоров",
    isolated: "изолирован",
    pending: "ожидает",
    platform_managed: "платформенный",
    rejected: "отклонено",
    revoked: "отозвано",
    running: "работает",
    customer_managed: "клиентский",
    stopped: "остановлено",
    unknown: "неизвестно",
  };
  return labels[value] || value;
}
