"use client"

import { useCallback, useEffect, useMemo, useRef, useState } from "react"
import Link from "next/link"
import { PageHeader } from "@/components/page-header"
import {
  Card, CardContent, CardHeader, CardTitle, CardDescription,
} from "@/components/ui/card"
import { Button, buttonVariants } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { useDataSource } from "@/lib/data-source"
import { useEvoBGP, type EvoBgpSavePayload, type EvoBgpTestDraft } from "@/lib/evobgp-context"
import { DEFAULT_ROUTE_AI_OPTIMIZER_SETTINGS } from "@/lib/route-optimizer-data"
import { Separator } from "@/components/ui/separator"
import {
  Sheet, SheetContent, SheetHeader, SheetTitle, SheetDescription, SheetFooter,
} from "@/components/ui/sheet"
import { Flag } from "@/components/flag"
import { StatusDot } from "@/components/status-dot"
import { servers } from "@/lib/data"
import {
  SaveIcon, PencilIcon, TrashIcon, PlusIcon, CheckIcon, CopyIcon,
  XIcon, AlertCircleIcon, ShieldIcon, EyeIcon, EyeOffIcon, WrenchIcon, UserIcon,
  ServerIcon, LayoutDashboardIcon, RefreshCwIcon, CableIcon, LoaderCircleIcon,
  DownloadIcon, UploadIcon,
} from "lucide-react"
import { cn } from "@/lib/utils"
import { requestJson } from "@/shared/api/http-client"
import { downloadSystemDatabaseBackup, restoreSystemDatabaseBackup } from "@/shared/api/system-database"
import { toast } from "sonner"

// ─── types ────────────────────────────────────────────────────────────────────

type Role     = "admin" | "operator" | "viewer"
type PermLevel = "none" | "read" | "write"

interface SectionPerm { section: string; level: PermLevel }
interface ServerPerm  { serverId: string; level: PermLevel }

interface User {
  id: string; name: string; login: string; email: string
  role: Role; last: string; avatar: string; active: boolean
  sections: SectionPerm[]; servers: ServerPerm[]
  subUsers: SubUser[]
}

interface ApiKey { id: string; name: string; prefix: string; created: string; last: string; scopes: string[] }

// Подчинённый пользователь — учётка для подключения устройства к JH через GRE
interface SubUser {
  id: string
  login: string
  password: string
  description: string   // "офисный роутер", "склад", и т.п.
  jhServerIds: string[] // на каких JH зарегистрирована учётка
  clientIp: string      // назначенный IP внутри туннеля
  active: boolean
  lastSeen: string | null
}

// ─── section definitions ──────────────────────────────────────────────────────

const SECTION_GROUPS: { group: string; icon: React.ReactNode; items: string[] }[] = [
  { group: "Обзор",       icon: <LayoutDashboardIcon className="size-3" />, items: ["Дашборд", "Трафик", "Карта сети", "Мониторинг"] },
  { group: "Данные",      icon: <EyeIcon className="size-3" />,             items: ["Домены", "IP-диапазоны", "ASN", "Communities"] },
  { group: "Управление",  icon: <WrenchIcon className="size-3" />,          items: ["Серверы", "Фильтры", "Firewall", "GRE-туннели", "Бэкапы"] },
  { group: "Инструменты", icon: <ShieldIcon className="size-3" />,          items: ["Оптимизатор маршрутов", "OSPF", "Диагностика GRE", "Терминал"] },
  { group: "Система",     icon: <ServerIcon className="size-3" />,          items: ["Оповещения", "Сбор данных", "Настройки"] },
]

const ALL_SECTIONS = SECTION_GROUPS.flatMap(g => g.items)

// ─── default permissions by role ──────────────────────────────────────────────

function defaultSections(role: Role): SectionPerm[] {
  return ALL_SECTIONS.map(section => {
    let level: PermLevel = "none"
    if (role === "admin")    level = "write"
    else if (role === "operator") level = ["Серверы","Фильтры","Firewall","GRE-туннели","Бэкапы","Диагностика GRE","Оптимизатор маршрутов","OSPF"].includes(section) ? "write" : "read"
    else if (role === "viewer")   level = ["Настройки","Терминал"].includes(section) ? "none" : "read"
    return { section, level }
  })
}

function defaultServers(role: Role): ServerPerm[] {
  return servers.map(s => ({
    serverId: s.id,
    level: role === "admin" ? "write" : role === "operator" ? "read" : "read" as PermLevel,
  }))
}

// ─── initial data ──────────────────────────────────────────────────────────────

const INIT_USERS: User[] = [
  {
    id: "u1", name: "Александр Коротаев", login: "a.korotaev", email: "a.korotaev@company.io",
    role: "admin", last: "сейчас", avatar: "АК", active: true,
    sections: defaultSections("admin"), servers: defaultServers("admin"),
    subUsers: [
      { id: "su1", login: "gre-office-msk",  password: "xK9#mQ2$vLp8",  description: "Офис MSK",      jhServerIds: ["srv1","srv7"], clientIp: "10.210.0.2",  active: true,  lastSeen: "5м назад"   },
      { id: "su2", login: "gre-datacenter",  password: "pW3@jT7!hD5k",  description: "ЦОД Tier-2",    jhServerIds: ["srv1"],       clientIp: "10.210.0.6",  active: true,  lastSeen: "1ч назад"   },
      { id: "su3", login: "gre-warehouse",   password: "rN6%bF2*cM8s",  description: "Склад Химки",   jhServerIds: ["srv7"],       clientIp: "10.210.1.2",  active: false, lastSeen: "3 дн назад" },
    ],
  },
  {
    id: "u2", name: "Дмитрий Фёдоров", login: "d.fedorov", email: "d.fedorov@company.io",
    role: "operator", last: "2ч назад", avatar: "ДФ", active: true,
    sections: defaultSections("operator"), servers: defaultServers("operator"),
    subUsers: [
      { id: "su4", login: "gre-spb-branch",  password: "qA4^eU9#wG1o",  description: "Филиал SPB",    jhServerIds: ["srv1","srv7"], clientIp: "10.210.0.10", active: true,  lastSeen: "20м назад"  },
    ],
  },
  {
    id: "u3", name: "Мария Соколова", login: "m.sokolova", email: "m.sokolova@company.io",
    role: "viewer", last: "вчера", avatar: "МС", active: true,
    sections: defaultSections("viewer"), servers: defaultServers("viewer"),
    subUsers: [],
  },
  {
    id: "u4", name: "Игорь Петров", login: "i.petrov", email: "i.petrov@company.io",
    role: "operator", last: "3 дн назад", avatar: "ИП", active: false,
    sections: defaultSections("operator"), servers: defaultServers("operator"),
    subUsers: [
      { id: "su5", login: "gre-retail-01",   password: "bF7!nK3@mZ9v",  description: "Магазин #1",    jhServerIds: ["srv1"],       clientIp: "10.210.0.14", active: false, lastSeen: null         },
    ],
  },
]

const INIT_API_KEYS: ApiKey[] = [
  { id: "k1", name: "Monitoring Script",  prefix: "rl_live_mU9k2…", created: "12 дн назад", last: "2м назад", scopes: ["servers:read", "probes:read"] },
  { id: "k2", name: "CI/CD deploy hook",  prefix: "rl_live_vB3p8…", created: "1 мес назад", last: "вчера",    scopes: ["filters:write", "domains:write"] },
  { id: "k3", name: "Grafana datasource", prefix: "rl_live_xK7r1…", created: "2 мес назад", last: "сейчас",   scopes: ["traffic:read", "servers:read"] },
]

const ROLE_LABEL: Record<Role, string> = { admin: "Администратор", operator: "Оператор", viewer: "Наблюдатель" }
const ROLE_COLOR: Record<Role, string> = {
  admin:    "bg-violet-500/10 text-violet-600 dark:text-violet-400 border border-violet-500/20",
  operator: "bg-sky-500/10 text-sky-600 dark:text-sky-400 border border-sky-500/20",
  viewer:   "bg-muted text-muted-foreground border border-border",
}

const PERM_OPTS: { v: PermLevel; label: string }[] = [
  { v: "none",  label: "Нет"       },
  { v: "read",  label: "Просмотр"  },
  { v: "write", label: "Управление"},
]

const PERM_COLOR: Record<PermLevel, string> = {
  none:  "bg-muted text-muted-foreground",
  read:  "bg-sky-500/10 text-sky-600 dark:text-sky-400",
  write: "bg-emerald-500/10 text-emerald-600 dark:text-emerald-400",
}

const SECTIONS_NAV = ["Общие", "EvoBGP", "Уведомления", "Пользователи", "API-ключи", "Безопасность"] as const
type NavSection = typeof SECTIONS_NAV[number]

function makeApiFetch(backendUrl: string) {
  return async function apiFetch<T>(path: string, init?: RequestInit): Promise<T> {
    return requestJson<T>(backendUrl, path, init)
  }
}

// ─── small components ─────────────────────────────────────────────────────────

function Toggle({ checked, onChange }: { checked: boolean; onChange: (v: boolean) => void }) {
  return (
    <button type="button" onClick={() => onChange(!checked)}
      className={cn("relative inline-flex h-5 w-9 shrink-0 rounded-full border-2 border-transparent transition-colors cursor-pointer",
        checked ? "bg-primary" : "bg-input")}>
      <span className={cn("pointer-events-none block h-4 w-4 rounded-full bg-white shadow-sm transition-transform",
        checked ? "translate-x-4" : "translate-x-0")} />
    </button>
  )
}

function SettingRow({ label, description, children }: { label: string; description?: string; children: React.ReactNode }) {
  return (
    <div className="flex items-center justify-between gap-4 py-3.5">
      <div className="min-w-0">
        <p className="text-sm font-medium">{label}</p>
        {description && <p className="text-xs text-muted-foreground mt-0.5">{description}</p>}
      </div>
      <div className="shrink-0">{children}</div>
    </div>
  )
}

function PermPills({ value, onChange, disabled }: { value: PermLevel; onChange: (v: PermLevel) => void; disabled?: boolean }) {
  return (
    <div className={cn("flex rounded border border-input overflow-hidden h-6", disabled && "opacity-40 pointer-events-none")}>
      {PERM_OPTS.map((o, i) => (
        <button
          key={o.v} type="button" onClick={() => onChange(o.v)}
          className={cn(
            "px-2 text-[11px] font-medium transition-colors",
            i < PERM_OPTS.length - 1 && "border-r border-input",
            value === o.v
              ? o.v === "write" ? "bg-emerald-600 text-white dark:bg-emerald-500"
              : o.v === "read"  ? "bg-sky-600 text-white dark:bg-sky-500"
              :                   "bg-muted-foreground/70 text-white"
              : "text-muted-foreground hover:bg-muted",
          )}
        >{o.label}</button>
      ))}
    </div>
  )
}

function AvatarCircle({ avatar, active }: { avatar: string; active: boolean }) {
  return (
    <div className="relative shrink-0">
      <div className={cn(
        "size-8 rounded-full flex items-center justify-center text-white text-[10px] font-semibold",
        "bg-gradient-to-br from-blue-500 to-violet-500",
        !active && "opacity-50",
      )}>{avatar}</div>
      {!active && (
        <span className="absolute -bottom-0.5 -right-0.5 size-2.5 rounded-full bg-muted-foreground/50 border-2 border-background" />
      )}
    </div>
  )
}

// ─── user sheet ───────────────────────────────────────────────────────────────

interface UserForm {
  name: string; login: string; email: string; role: Role; active: boolean
  sections: SectionPerm[]; servers: ServerPerm[]
  subUsers: SubUser[]
}

function emptyForm(): UserForm {
  return { name: "", login: "", email: "", role: "viewer", active: true,
    sections: defaultSections("viewer"), servers: defaultServers("viewer"), subUsers: [] }
}

function genPassword(): string {
  const chars = "abcdefghijkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ23456789!@#$%"
  return Array.from({ length: 16 }, () => chars[Math.floor(Math.random() * chars.length)]).join("")
}

function genSubLogin(userLogin: string, existing: SubUser[]): string {
  const base = `gre-${userLogin.split(".").pop() ?? "client"}`
  const n = existing.filter(s => s.login.startsWith(base)).length
  return n === 0 ? base : `${base}-${String(n + 1).padStart(2, "0")}`
}

function UserSheet({ open, user, onSave, onClose }: {
  open: boolean
  user: User | null   // null = create
  onSave: (f: UserForm) => void
  onClose: () => void
}) {
  const isCreate = user === null
  const [tab, setTab] = useState<"profile" | "sections" | "servers" | "subusers">("profile")
  const [form, setForm] = useState<UserForm>(() =>
    user ? {
      name: user.name, login: user.login, email: user.email, role: user.role,
      active: user.active,
      sections: user.sections.map(s => ({ ...s })),
      servers:  user.servers.map(s => ({ ...s })),
      subUsers: user.subUsers.map(s => ({ ...s })),
    } : emptyForm()
  )
  // sub-user add form state
  const [addSubOpen,    setAddSubOpen]    = useState(false)
  const [newSubLogin,   setNewSubLogin]   = useState("")
  const [newSubPwd,     setNewSubPwd]     = useState("")
  const [newSubDesc,    setNewSubDesc]    = useState("")
  const [newSubJhs,     setNewSubJhs]     = useState<string[]>([])
  const [newSubIp,      setNewSubIp]      = useState("")
  const [revealedIds,   setRevealedIds]   = useState<Set<string>>(new Set())
  const [errors, setErrors] = useState<Partial<Record<keyof UserForm, string>>>({})

  const setField = <K extends keyof UserForm>(k: K, v: UserForm[K]) => {
    setForm(f => ({ ...f, [k]: v }))
    if (errors[k]) setErrors(e => ({ ...e, [k]: undefined }))
  }

  // When role changes → reset permissions to defaults
  const setRole = (role: Role) => {
    setForm(f => ({ ...f, role, sections: defaultSections(role), servers: defaultServers(role) }))
  }

  const setSectionPerm = (section: string, level: PermLevel) => {
    setForm(f => ({
      ...f,
      sections: f.sections.map(s => s.section === section ? { ...s, level } : s),
    }))
  }

  const setServerPerm = (serverId: string, level: PermLevel) => {
    setForm(f => ({
      ...f,
      servers: f.servers.map(s => s.serverId === serverId ? { ...s, level } : s),
    }))
  }

  const setAllSections = (level: PermLevel) => {
    setForm(f => ({ ...f, sections: f.sections.map(s => ({ ...s, level })) }))
  }

  const setAllServers = (level: PermLevel) => {
    setForm(f => ({ ...f, servers: f.servers.map(s => ({ ...s, level })) }))
  }

  const validate = () => {
    const e: Partial<Record<keyof UserForm, string>> = {}
    if (!form.name.trim())  e.name  = "Обязательное поле"
    if (!form.login.trim()) e.login = "Обязательное поле"
    if (!form.email.trim()) e.email = "Обязательное поле"
    setErrors(e)
    return !Object.keys(e).length
  }

  const handleSave = () => { if (validate()) onSave(form) }

  const isAdmin = form.role === "admin"

  const jhServers = servers.filter(s => s.type === "jump-host" && s.enabled)

  const addSubUser = () => {
    if (!newSubLogin.trim() || !newSubPwd.trim() || newSubJhs.length === 0) return
    const sub: SubUser = {
      id: `su${Date.now()}`,
      login: newSubLogin.trim(),
      password: newSubPwd,
      description: newSubDesc.trim(),
      jhServerIds: [...newSubJhs],
      clientIp: newSubIp.trim(),
      active: true,
      lastSeen: null,
    }
    setForm(f => ({ ...f, subUsers: [...f.subUsers, sub] }))
    setAddSubOpen(false)
    setNewSubLogin(""); setNewSubPwd(""); setNewSubDesc(""); setNewSubIp(""); setNewSubJhs([])
  }

  const toggleNewSubJh = (id: string) =>
    setNewSubJhs(prev => prev.includes(id) ? prev.filter(x => x !== id) : [...prev, id])

  const removeSubUser = (id: string) =>
    setForm(f => ({ ...f, subUsers: f.subUsers.filter(s => s.id !== id) }))

  const toggleSubUser = (id: string) =>
    setForm(f => ({ ...f, subUsers: f.subUsers.map(s => s.id === id ? { ...s, active: !s.active } : s) }))

  const toggleReveal = (id: string) =>
    setRevealedIds(prev => {
      const next = new Set(prev); if (next.has(id)) next.delete(id); else next.add(id); return next
    })

  const TABS = [
    { id: "profile",  label: "Профиль"  },
    { id: "sections", label: "Разделы"  },
    { id: "servers",  label: "Серверы"  },
    { id: "subusers", label: "GRE-клиенты", badge: form.subUsers.length || undefined },
  ] as const

  return (
    <Sheet open={open} onOpenChange={v => { if (!v) onClose() }}>
      <SheetContent side="right" className="sm:max-w-[520px] p-0 flex flex-col" showCloseButton={false}>

        {/* header */}
        <SheetHeader className="px-5 pt-5 pb-0 border-b shrink-0">
          <div className="flex items-start justify-between gap-2 pb-4">
            <div className="flex items-center gap-3">
              {!isCreate && user && (
                <AvatarCircle avatar={user.avatar} active={form.active} />
              )}
              <div>
                <SheetTitle className="text-base leading-tight">
                  {isCreate ? "Новый пользователь" : form.name || "—"}
                </SheetTitle>
                <SheetDescription className="text-xs mt-0.5">
                  {isCreate ? "Заполните данные и настройте доступ" : `@${form.login}`}
                </SheetDescription>
              </div>
            </div>
            <Button variant="ghost" size="icon-sm" onClick={onClose} className="shrink-0 mt-0.5">
              <XIcon className="size-4" />
            </Button>
          </div>

          {/* tab bar */}
          <div className="flex gap-0 -mb-px">
            {TABS.map(t => (
              <button key={t.id} onClick={() => setTab(t.id as typeof tab)}
                className={cn(
                  "px-4 py-2 text-sm font-medium border-b-2 transition-colors flex items-center gap-1.5",
                  tab === t.id
                    ? "border-foreground text-foreground"
                    : "border-transparent text-muted-foreground hover:text-foreground",
                )}>
                {t.label}
                {"badge" in t && t.badge !== undefined && (
                  <span className={cn(
                    "text-[10px] font-semibold px-1.5 py-0.5 rounded-full tabular-nums",
                    tab === t.id
                      ? "bg-foreground/10"
                      : "bg-muted text-muted-foreground",
                  )}>{t.badge}</span>
                )}
              </button>
            ))}
          </div>
        </SheetHeader>

        {/* body */}
        <div className="flex-1 overflow-y-auto">

          {/* ── Profile tab ── */}
          {tab === "profile" && (
            <div className="px-5 py-5 flex flex-col gap-4">

              <Field label="Полное имя" error={errors.name}>
                <Input value={form.name} onChange={e => setField("name", e.target.value)}
                  placeholder="Иван Иванов" className="h-9" />
              </Field>

              <Field label="Логин" error={errors.login}>
                <Input value={form.login} onChange={e => setField("login", e.target.value)}
                  placeholder="i.ivanov" className="h-9 font-mono" />
              </Field>

              <Field label="Email" error={errors.email}>
                <Input value={form.email} onChange={e => setField("email", e.target.value)}
                  placeholder="i.ivanov@company.io" type="email" className="h-9" />
              </Field>

              <Separator />

              <Field label="Роль">
                <div className="flex gap-2 flex-wrap">
                  {(["viewer", "operator", "admin"] as Role[]).map(r => (
                    <button key={r} type="button" onClick={() => setRole(r)}
                      className={cn(
                        "px-3 py-1.5 rounded-md border text-xs font-medium transition-all",
                        form.role === r
                          ? r === "admin"    ? "bg-violet-500/10 text-violet-600 dark:text-violet-400 border-violet-500/30 ring-1 ring-violet-500/30"
                          : r === "operator" ? "bg-sky-500/10 text-sky-600 dark:text-sky-400 border-sky-500/30 ring-1 ring-sky-500/30"
                          :                   "bg-muted text-foreground border-border ring-1 ring-border"
                          : "border-border text-muted-foreground hover:bg-muted",
                      )}>
                      {ROLE_LABEL[r]}
                    </button>
                  ))}
                </div>
                <p className="text-[11px] text-muted-foreground mt-1.5">
                  {form.role === "admin"
                    ? "Полный доступ ко всем разделам и серверам, не ограничивается матрицей прав"
                    : form.role === "operator"
                    ? "Управление инфраструктурой согласно выданным правам"
                    : "Только просмотр согласно выданным правам"}
                </p>
              </Field>

              <Separator />

              <Field label="Статус учётной записи">
                <div className="flex items-center gap-3">
                  <Toggle checked={form.active} onChange={v => setField("active", v)} />
                  <span className={cn("text-xs font-medium", form.active ? "text-emerald-600 dark:text-emerald-400" : "text-muted-foreground")}>
                    {form.active ? "Активна" : "Заблокирована"}
                  </span>
                </div>
              </Field>
            </div>
          )}

          {/* ── Sections tab ── */}
          {tab === "sections" && (
            <div className="flex flex-col">
              {/* bulk actions */}
              <div className="flex items-center gap-2 px-4 py-2.5 border-b bg-muted/30">
                <span className="text-xs text-muted-foreground mr-1">Выбрать всё:</span>
                {PERM_OPTS.map(o => (
                  <button key={o.v} type="button" onClick={() => setAllSections(o.v)}
                    disabled={isAdmin}
                    className={cn(
                      "text-[11px] px-2 py-0.5 rounded border transition-colors",
                      isAdmin ? "opacity-30 cursor-not-allowed" : "hover:bg-muted cursor-pointer",
                      PERM_COLOR[o.v], "border-border",
                    )}>
                    {o.label}
                  </button>
                ))}
                {isAdmin && (
                  <span className="ml-auto text-[11px] text-violet-600 dark:text-violet-400 flex items-center gap-1">
                    <ShieldIcon className="size-3" />Администратор имеет полный доступ
                  </span>
                )}
              </div>

              {SECTION_GROUPS.map(group => (
                <div key={group.group}>
                  {/* group header */}
                  <div className="flex items-center gap-2 px-4 py-1.5 bg-muted/20 border-b">
                    <span className="text-muted-foreground">{group.icon}</span>
                    <span className="text-[10px] font-semibold uppercase tracking-widest text-muted-foreground">
                      {group.group}
                    </span>
                  </div>
                  {/* section rows */}
                  <div className="divide-y divide-border/60">
                    {group.items.map(section => {
                      const perm = form.sections.find(s => s.section === section)
                      const level = perm?.level ?? "none"
                      return (
                        <div key={section} className="flex items-center justify-between px-4 py-2.5 hover:bg-muted/20 transition-colors">
                          <span className="text-sm">{section}</span>
                          <PermPills value={level} onChange={v => setSectionPerm(section, v)} disabled={isAdmin} />
                        </div>
                      )
                    })}
                  </div>
                </div>
              ))}
            </div>
          )}

          {/* ── Servers tab ── */}
          {tab === "servers" && (
            <div className="flex flex-col">
              {/* bulk actions */}
              <div className="flex items-center gap-2 px-4 py-2.5 border-b bg-muted/30">
                <span className="text-xs text-muted-foreground mr-1">Выбрать всё:</span>
                {PERM_OPTS.map(o => (
                  <button key={o.v} type="button" onClick={() => setAllServers(o.v)}
                    disabled={isAdmin}
                    className={cn(
                      "text-[11px] px-2 py-0.5 rounded border transition-colors",
                      isAdmin ? "opacity-30 cursor-not-allowed" : "hover:bg-muted cursor-pointer",
                      PERM_COLOR[o.v], "border-border",
                    )}>
                    {o.label}
                  </button>
                ))}
                {isAdmin && (
                  <span className="ml-auto text-[11px] text-violet-600 dark:text-violet-400 flex items-center gap-1">
                    <ShieldIcon className="size-3" />Администратор имеет полный доступ
                  </span>
                )}
              </div>

              <div className="divide-y divide-border/60">
                {servers.map(srv => {
                  const perm  = form.servers.find(s => s.serverId === srv.id)
                  const level = perm?.level ?? "none"
                  return (
                    <div key={srv.id} className="flex items-center justify-between gap-3 px-4 py-2.5 hover:bg-muted/20 transition-colors">
                      <div className="flex items-center gap-2.5 min-w-0">
                        <StatusDot status={srv.status} />
                        {srv.country && <Flag code={srv.country} size={14} />}
                        <div className="min-w-0">
                          <p className="text-sm font-medium truncate leading-tight">{srv.name}</p>
                          <p className="text-[11px] font-mono text-muted-foreground">{srv.host} · {srv.site}</p>
                        </div>
                      </div>
                      <PermPills value={level} onChange={v => setServerPerm(srv.id, v)} disabled={isAdmin} />
                    </div>
                  )
                })}
              </div>
            </div>
          )}

          {/* ── GRE-клиенты tab ── */}
          {tab === "subusers" && (
            <div className="flex flex-col">

              {/* hint */}
              <div className="flex items-center gap-2 px-4 py-2.5 border-b bg-muted/30">
                <CableIcon className="size-3.5 text-muted-foreground shrink-0" />
                <p className="text-[11px] text-muted-foreground">
                  Учётные записи для подключения устройств к JH через GRE
                </p>
              </div>

              {/* table header */}
              {form.subUsers.length > 0 && (
                <div className="grid items-center gap-2 px-4 py-1.5 bg-muted/20 border-b text-[10px] font-semibold uppercase tracking-widest text-muted-foreground"
                  style={{ gridTemplateColumns: "1fr 130px 120px 90px 36px 32px" }}>
                  <span>Логин / описание</span>
                  <span>Пароль</span>
                  <span>JH-серверы</span>
                  <span>IP-клиента</span>
                  <span />
                  <span />
                </div>
              )}

              {/* rows */}
              <div className="divide-y divide-border/60">
                {form.subUsers.length === 0 && !addSubOpen && (
                  <div className="flex flex-col items-center justify-center py-12 gap-2 text-muted-foreground">
                    <CableIcon className="size-6 opacity-20" />
                    <p className="text-sm">Нет GRE-клиентов</p>
                    <p className="text-xs opacity-60">Добавьте учётки для подключения устройств</p>
                  </div>
                )}

                {form.subUsers.map(su => {
                  const jhs     = servers.filter(s => su.jhServerIds.includes(s.id))
                  const revealed = revealedIds.has(su.id)
                  return (
                    <div key={su.id}
                      className={cn(
                        "grid items-center gap-2 px-4 py-2.5 hover:bg-muted/20 transition-colors",
                        !su.active && "opacity-50",
                      )}
                      style={{ gridTemplateColumns: "1fr 130px 120px 90px 36px 32px" }}>

                      {/* login + description */}
                      <div className="min-w-0">
                        <p className="text-xs font-mono font-medium truncate">{su.login}</p>
                        {su.description && (
                          <p className="text-[11px] text-muted-foreground truncate">{su.description}</p>
                        )}
                        {su.lastSeen && (
                          <p className="text-[10px] text-muted-foreground/50">{su.lastSeen}</p>
                        )}
                      </div>

                      {/* password */}
                      <div className="flex items-center gap-1 min-w-0">
                        <span className="font-mono text-[11px] truncate flex-1">
                          {revealed ? su.password : "••••••••••••"}
                        </span>
                        <button onClick={() => toggleReveal(su.id)}
                          className="text-muted-foreground/50 hover:text-muted-foreground shrink-0 transition-colors">
                          {revealed
                            ? <EyeOffIcon className="size-3" />
                            : <EyeIcon    className="size-3" />}
                        </button>
                        <button onClick={() => navigator.clipboard.writeText(su.password).catch(() => {})}
                          className="text-muted-foreground/50 hover:text-muted-foreground shrink-0 transition-colors">
                          <CopyIcon className="size-3" />
                        </button>
                      </div>

                      {/* JH servers */}
                      <div className="flex flex-wrap gap-1 min-w-0">
                        {jhs.length === 0
                          ? <span className="text-[11px] text-muted-foreground/40">—</span>
                          : jhs.map(jh => (
                            <span key={jh.id} className="inline-flex items-center gap-1 text-[10px] font-medium
                              bg-violet-500/10 text-violet-600 dark:text-violet-400 border border-violet-500/20
                              rounded px-1 py-0.5">
                              <Flag code={jh.country} size={10} />
                              {jh.name.split("-").slice(-1)[0]}
                            </span>
                          ))
                        }
                      </div>

                      {/* client IP */}
                      <span className="font-mono text-[11px] text-muted-foreground truncate">
                        {su.clientIp || "—"}
                      </span>

                      {/* active toggle */}
                      <Toggle checked={su.active} onChange={() => toggleSubUser(su.id)} />

                      {/* delete */}
                      <button onClick={() => removeSubUser(su.id)}
                        className="text-muted-foreground/40 hover:text-destructive transition-colors flex justify-end">
                        <TrashIcon className="size-3.5" />
                      </button>
                    </div>
                  )
                })}
              </div>

              {/* inline add form */}
              {addSubOpen ? (
                <div className="border-t bg-muted/20 px-4 py-4 flex flex-col gap-3">
                  <p className="text-xs font-medium text-muted-foreground">Новый GRE-клиент</p>

                  <div className="grid grid-cols-2 gap-2">
                    <div className="flex flex-col gap-1">
                      <label className="text-[10px] text-muted-foreground">Логин</label>
                      <Input className="h-8 text-xs font-mono" placeholder="gre-office-msk"
                        value={newSubLogin} onChange={e => setNewSubLogin(e.target.value)} />
                    </div>
                    <div className="flex flex-col gap-1">
                      <label className="text-[10px] text-muted-foreground">Описание</label>
                      <Input className="h-8 text-xs" placeholder="Офис MSK"
                        value={newSubDesc} onChange={e => setNewSubDesc(e.target.value)} />
                    </div>
                  </div>

                  <div className="flex flex-col gap-1">
                    <label className="text-[10px] text-muted-foreground">Пароль</label>
                    <div className="flex gap-1.5">
                      <Input className="h-8 text-xs font-mono flex-1" placeholder="••••••••"
                        value={newSubPwd} onChange={e => setNewSubPwd(e.target.value)} />
                      <Button variant="outline" size="sm" className="h-8 px-2 shrink-0"
                        onClick={() => setNewSubPwd(genPassword())} title="Сгенерировать пароль">
                        <RefreshCwIcon className="size-3.5" />
                      </Button>
                    </div>
                  </div>

                  <div className="flex flex-col gap-1">
                    <label className="text-[10px] text-muted-foreground">
                      JH-серверы
                      <span className="ml-1 text-muted-foreground/50">(можно выбрать несколько)</span>
                    </label>
                    <div className="flex flex-col gap-1 rounded-md border border-input bg-background px-2 py-1.5">
                      {jhServers.map(s => {
                        const checked = newSubJhs.includes(s.id)
                        return (
                          <label key={s.id}
                            className="flex items-center gap-2 py-0.5 cursor-pointer hover:text-foreground transition-colors">
                            <input type="checkbox" checked={checked}
                              onChange={() => toggleNewSubJh(s.id)}
                              className="rounded border-input accent-primary" />
                            <Flag code={s.country} size={12} />
                            <span className="font-mono text-xs">{s.name}</span>
                            <span className="text-[10px] text-muted-foreground">{s.site}</span>
                          </label>
                        )
                      })}
                    </div>
                    {newSubJhs.length === 0 && (
                      <p className="text-[10px] text-destructive">Выберите хотя бы один JH-сервер</p>
                    )}
                  </div>

                  <div className="flex flex-col gap-1">
                    <label className="text-[10px] text-muted-foreground">IP-клиента</label>
                    <Input className="h-8 text-xs font-mono" placeholder="10.210.0.18"
                      value={newSubIp} onChange={e => setNewSubIp(e.target.value)} />
                  </div>

                  <div className="flex gap-2 pt-1">
                    <Button variant="outline" size="sm" className="flex-1"
                      onClick={() => { setAddSubOpen(false); setNewSubLogin(""); setNewSubPwd(""); setNewSubDesc(""); setNewSubIp(""); setNewSubJhs([]) }}>
                      Отмена
                    </Button>
                    <Button size="sm" className="flex-1"
                      disabled={!newSubLogin.trim() || !newSubPwd.trim() || newSubJhs.length === 0}
                      onClick={addSubUser}>
                      <PlusIcon className="size-3.5" />Добавить
                    </Button>
                  </div>
                </div>
              ) : (
                <button
                  onClick={() => {
                    setNewSubLogin(genSubLogin(form.login, form.subUsers))
                    setNewSubPwd(genPassword())
                    setNewSubJhs(jhServers.length > 0 ? [jhServers[0].id] : [])
                    setAddSubOpen(true)
                  }}
                  className="w-full flex items-center gap-2 px-4 py-2.5 text-xs text-muted-foreground hover:text-foreground hover:bg-muted/20 transition-colors border-t">
                  <PlusIcon className="size-3.5" />Добавить GRE-клиента
                </button>
              )}
            </div>
          )}
        </div>

        {/* footer */}
        <SheetFooter className="px-5 py-4 border-t shrink-0 gap-2">
          <Button variant="outline" onClick={onClose} className="flex-1">Отмена</Button>
          <Button onClick={handleSave} className="flex-1">
            <CheckIcon className="size-4" />
            {isCreate ? "Создать" : "Сохранить"}
          </Button>
        </SheetFooter>
      </SheetContent>
    </Sheet>
  )
}

// ─── helper ───────────────────────────────────────────────────────────────────

function Field({ label, error, children }: { label: string; error?: string; children: React.ReactNode }) {
  return (
    <div className="flex flex-col gap-1.5">
      <label className="text-xs font-medium">{label}</label>
      {children}
      {error && (
        <p className="text-xs text-destructive flex items-center gap-1">
          <AlertCircleIcon className="size-3" />{error}
        </p>
      )}
    </div>
  )
}

// ─── delete confirm ───────────────────────────────────────────────────────────

function DatabaseRestoreConfirm({
  filename,
  busy,
  onConfirm,
  onCancel,
}: {
  filename: string
  busy?: boolean
  onConfirm: () => void
  onCancel: () => void
}) {
  return (
    <div className="fixed inset-0 z-50 flex items-center justify-center">
      <div className="absolute inset-0 bg-black/40 backdrop-blur-sm" onClick={onCancel} />
      <div className="relative z-10 w-full max-w-sm mx-4 bg-card rounded-xl border shadow-2xl p-5 flex flex-col gap-4">
        <div className="flex items-center gap-3">
          <div className="size-9 rounded-full bg-destructive/10 flex items-center justify-center shrink-0">
            <AlertCircleIcon className="size-4 text-destructive" />
          </div>
          <div>
            <p className="text-sm font-semibold">Восстановить базу приложения?</p>
            <p className="text-xs text-muted-foreground mt-0.5 break-all">{filename}</p>
          </div>
        </div>
        <p className="text-xs text-muted-foreground">
          Текущие данные SQLite на бекенде будут полностью заменены содержимым файла. Рекомендуется сначала скачать
          актуальный бэкап.
        </p>
        <div className="flex gap-2">
          <Button variant="outline" className="flex-1" onClick={onCancel} disabled={busy}>Отмена</Button>
          <Button variant="destructive" className="flex-1" onClick={onConfirm} disabled={busy}>
            {busy ? <LoaderCircleIcon className="size-4 animate-spin" /> : null}
            {busy ? "Восстановление…" : "Восстановить"}
          </Button>
        </div>
      </div>
    </div>
  )
}

function DeleteConfirm({ user, onConfirm, onCancel }: { user: User; onConfirm: () => void; onCancel: () => void }) {
  return (
    <div className="fixed inset-0 z-50 flex items-center justify-center">
      <div className="absolute inset-0 bg-black/40 backdrop-blur-sm" onClick={onCancel} />
      <div className="relative z-10 w-full max-w-sm mx-4 bg-card rounded-xl border shadow-2xl p-5 flex flex-col gap-4">
        <div className="flex items-center gap-3">
          <div className="size-9 rounded-full bg-destructive/10 flex items-center justify-center shrink-0">
            <TrashIcon className="size-4 text-destructive" />
          </div>
          <div>
            <p className="text-sm font-semibold">Удалить пользователя?</p>
            <p className="text-xs text-muted-foreground mt-0.5">{user.name} · @{user.login}</p>
          </div>
        </div>
        <p className="text-xs text-muted-foreground">
          Это действие нельзя отменить. Пользователь потеряет доступ немедленно.
        </p>
        <div className="flex gap-2">
          <Button variant="outline" className="flex-1" onClick={onCancel}>Отмена</Button>
          <Button variant="destructive" className="flex-1" onClick={onConfirm}>Удалить</Button>
        </div>
      </div>
    </div>
  )
}

// ─── page ─────────────────────────────────────────────────────────────────────

export default function SettingsPage() {
  const [section,  setSection]  = useState<NavSection>("Общие")
  const [saved,    setSaved]    = useState(false)
  const [copied,   setCopied]   = useState<string | null>(null)

  // data source
  const { mode, setMode, backendUrl, setBackendUrl, backendUrlLocked, mockModeAvailable, backendStatus, checkBackend } = useDataSource()
  const evo = useEvoBGP()
  const [evoBaseDraft, setEvoBaseDraft] = useState("")
  const [evoEnabledDraft, setEvoEnabledDraft] = useState(false)
  const [evoKeyDraft, setEvoKeyDraft] = useState("")
  const [evoSaveBusy, setEvoSaveBusy] = useState(false)
  const [evoSaveErr, setEvoSaveErr] = useState<string | null>(null)
  const [urlDraft, setUrlDraft] = useState(backendUrl)
  const apiFetch = useMemo(() => makeApiFetch(backendUrl), [backendUrl])

  useEffect(() => {
    setUrlDraft(backendUrl)
  }, [backendUrl])

  const commitBackendUrl = useCallback(() => {
    const normalized = urlDraft.trim().replace(/\/$/, "")
    setUrlDraft(normalized)
    setBackendUrl(normalized)
    void checkBackend()
  }, [urlDraft, setBackendUrl, checkBackend])
  const [evoTestResult, setEvoTestResult] = useState<{ ok: boolean; message: string } | null>(null)
  const [evoBusy, setEvoBusy] = useState<"test" | "refresh" | null>(null)
  const [showEvoKey, setShowEvoKey] = useState(false)

  // general
  const [lang,         setLang]         = useState("ru")
  const [theme,        setTheme]        = useState("system")
  const [timezone,     setTimezone]     = useState("Europe/Moscow")
  const [refreshSec,   setRefreshSec]   = useState("30")
  const [probeTimeout, setProbeTimeout] = useState("5")
  const [dbBackupBusy, setDbBackupBusy] = useState(false)
  const [dbRestoreBusy, setDbRestoreBusy] = useState(false)
  const [dbRestoreFile, setDbRestoreFile] = useState<File | null>(null)
  const dbRestoreInputRef = useRef<HTMLInputElement>(null)

  // notifications
  const [notifEmail,   setNotifEmail]   = useState(true)
  const [notifSlack,   setNotifSlack]   = useState(false)
  const [notifWh,      setNotifWh]      = useState(true)
  const [notifDegr,    setNotifDegr]    = useState(true)
  const [notifOffline, setNotifOffline] = useState(true)
  const [notifBgp,     setNotifBgp]     = useState(true)
  const [notifBackup,  setNotifBackup]  = useState(false)

  // users
  const [users,        setUsers]       = useState<User[]>(INIT_USERS)
  const [sheetOpen,    setSheetOpen]   = useState(false)
  const [editUser,     setEditUser]    = useState<User | null>(null)   // null = create mode
  const [deleteTarget, setDeleteTarget]= useState<User | null>(null)

  // api keys
  const [apiKeys, setApiKeys] = useState<ApiKey[]>(INIT_API_KEYS)

  // security
  const [mfa,      setMfa]      = useState(true)
  const [sessMin,  setSessMin]  = useState("480")
  const [ipAllow,  setIpAllow]  = useState("10.0.0.0/8\n192.168.0.0/16")
  const [auditLog, setAuditLog] = useState(true)

  const handleCopy = (text: string) => {
    navigator.clipboard.writeText(text).catch(() => {})
    setCopied(text); setTimeout(() => setCopied(null), 1500)
    toast.success("Скопировано в буфер обмена")
  }

  const markSaved = useCallback(() => {
    setSaved(true)
    toast.success("Настройки сохранены")
    setTimeout(() => setSaved(false), 2000)
  }, [])

  const handleUserSave = (form: UserForm) => {
    if (!editUser) {
      const initials = form.name.split(" ").map(p => p[0] ?? "").slice(0, 2).join("").toUpperCase()
      setUsers(prev => [...prev, {
        id: "u" + Date.now(), ...form,
        last: "только что", avatar: initials || "??",
      }])
    } else {
      setUsers(prev => prev.map(u => u.id === editUser.id ? { ...u, ...form } : u))
    }
    setSheetOpen(false)
  }

  // total sub-users count for summary
  const totalSubUsers = users.reduce((s, u) => s + u.subUsers.length, 0)

  useEffect(() => {
    if (section !== "EvoBGP") return
    if (mode === "live" && backendStatus === true) queueMicrotask(() => { void evo.loadSettings() })
  }, [section, mode, backendStatus, evo.loadSettings])

  useEffect(() => {
    if (section !== "EvoBGP" || !evo.settingsLoaded) return
    setEvoBaseDraft(evo.baseUrl)
    setEvoEnabledDraft(evo.enabled)
    setEvoKeyDraft("")
    setEvoSaveErr(null)
  }, [section, evo.settingsLoaded, evo.baseUrl, evo.enabled])

  const handleSave = useCallback(async () => {
    if (section === "EvoBGP") {
      if (mode !== "live" || backendStatus !== true) {
        markSaved()
        return
      }
      setEvoSaveBusy(true)
      setEvoSaveErr(null)
      try {
        const patch: EvoBgpSavePayload = {
          baseUrl: evoBaseDraft.trim(),
          enabled: evoEnabledDraft,
        }
        if (evoKeyDraft.trim()) patch.apiKey = evoKeyDraft.trim()
        await evo.saveSettings(patch)
        setEvoKeyDraft("")
        markSaved()
      } catch (e) {
        setEvoSaveErr(e instanceof Error ? e.message : "Ошибка сохранения")
      } finally {
        setEvoSaveBusy(false)
      }
      return
    }
    markSaved()
  }, [
    section,
    mode,
    backendStatus,
    evoBaseDraft,
    evoEnabledDraft,
    evoKeyDraft,
    markSaved,
    evo.saveSettings,
  ])

  const systemDbAvailable = mode === "live" && backendStatus === true

  const handleSystemDatabaseBackup = useCallback(async () => {
    if (!systemDbAvailable) return
    setDbBackupBusy(true)
    try {
      const { blob, filename } = await downloadSystemDatabaseBackup(backendUrl)
      const url = URL.createObjectURL(blob)
      const a = document.createElement("a")
      a.href = url
      a.download = filename
      a.click()
      URL.revokeObjectURL(url)
      toast.success("Бэкап базы приложения скачан")
    } catch (e) {
      toast.error(e instanceof Error ? e.message : "Не удалось создать бэкап")
    } finally {
      setDbBackupBusy(false)
    }
  }, [backendUrl, systemDbAvailable])

  const handleSystemDatabaseRestoreConfirm = useCallback(async () => {
    if (!dbRestoreFile || !systemDbAvailable) return
    setDbRestoreBusy(true)
    try {
      await restoreSystemDatabaseBackup(backendUrl, dbRestoreFile)
      toast.success("База приложения восстановлена")
      setDbRestoreFile(null)
      if (dbRestoreInputRef.current) dbRestoreInputRef.current.value = ""
    } catch (e) {
      toast.error(e instanceof Error ? e.message : "Не удалось восстановить базу")
    } finally {
      setDbRestoreBusy(false)
    }
  }, [backendUrl, dbRestoreFile, systemDbAvailable])

  const renderContent = () => {
    const ra = DEFAULT_ROUTE_AI_OPTIMIZER_SETTINGS

    // ── Общие ──
    if (section === "Общие") return (
      <div className="space-y-4">

      {/* ── Источник данных ── */}
      <Card>
        <CardHeader>
          <CardTitle className="text-base">Источник данных</CardTitle>
          <CardDescription className="text-xs">
            {mockModeAvailable
              ? "Переключите между живыми данными от бекенда и суррогатными моками из lib/data.ts"
              : "В продакшен-образе доступны только живые данные от бекенда"}
          </CardDescription>
        </CardHeader>
        <CardContent className="divide-y px-5">

          {/* mode toggle */}
          {mockModeAvailable ? (
            <SettingRow label="Режим данных" description="Моковые — статичные тестовые данные; Живые — RouterOS REST API через бекенд">
              <div className="flex rounded-md border border-input overflow-hidden h-8">
                {([["mock", "Моковые"], ["live", "Живые"]] as const).map(([v, l], i) => (
                  <button key={v} onClick={() => setMode(v)}
                    className={cn(
                      "px-3 text-xs transition-colors border-input",
                      i === 0 && "border-r",
                      mode === v
                        ? v === "live"
                          ? "bg-emerald-600 text-white dark:bg-emerald-500"
                          : "bg-primary text-primary-foreground"
                        : "text-muted-foreground hover:bg-muted",
                    )}>
                    {l}
                  </button>
                ))}
              </div>
            </SettingRow>
          ) : (
            <SettingRow label="Режим данных" description="В Docker-образе приложение работает только с живыми данными бекенда">
              <span className="inline-flex h-8 items-center rounded-md border border-input bg-emerald-600 px-3 text-xs text-white dark:bg-emerald-500">
                Живые
              </span>
            </SettingRow>
          )}

          {/* backend URL — visible in both modes so user can configure before switching */}
          <SettingRow
            label="URL бекенда"
            description={
              backendUrlLocked
                ? "В Docker-образе URL API задаётся через прокси фронтенда на backend; поле только для просмотра."
                : "Адрес Node.js/Fastify сервера (запускается командой npm run dev в /backend)"
            }
          >
            <div className="flex items-center gap-2">
              <Input
                className="w-56 h-8 text-sm font-mono"
                value={urlDraft}
                onChange={e => setUrlDraft(e.target.value)}
                onBlur={commitBackendUrl}
                onKeyDown={e => {
                  if (e.key === "Enter") {
                    e.preventDefault()
                    commitBackendUrl()
                  }
                }}
                readOnly={backendUrlLocked}
                placeholder="http://localhost:8000"
              />
              <Button variant="outline" size="sm" className="h-8 px-2.5 shrink-0"
                onClick={commitBackendUrl}
                title="Проверить соединение">
                <RefreshCwIcon className="size-3.5" />
              </Button>
            </div>
          </SettingRow>

          {/* connection status */}
          <SettingRow label="Статус бекенда">
            <div className="flex items-center gap-2">
              {backendStatus === undefined && (
                <span className="flex items-center gap-1.5 text-xs text-muted-foreground">
                  <span className="size-2 rounded-full bg-muted-foreground/40 inline-block" />
                  Не проверялось
                </span>
              )}
              {backendStatus === true && (
                <span className="flex items-center gap-1.5 text-xs text-emerald-600 dark:text-emerald-400">
                  <CheckIcon className="size-3.5" />Доступен
                </span>
              )}
              {backendStatus === false && (
                <span className="flex items-center gap-1.5 text-xs text-destructive">
                  <XIcon className="size-3.5" />Недоступен
                </span>
              )}
              <Button variant="ghost" size="sm" className="h-7 px-2 text-xs text-muted-foreground"
                onClick={checkBackend}>
                Проверить
              </Button>
            </div>
          </SettingRow>

          {/* hint when live but backend unreachable */}
          {mode === "live" && backendStatus === false && (
            <div className="flex items-start gap-2 py-3 text-xs text-amber-600 dark:text-amber-400">
              <AlertCircleIcon className="size-3.5 mt-0.5 shrink-0" />
              <span>Бекенд недоступен — данные будут отображаться из кеша или моков. Запустите бекенд: <code className="font-mono bg-muted px-1 rounded">cd backend && npm run dev</code></span>
            </div>
          )}
        </CardContent>
      </Card>

      {/* ── Основные настройки ── */}
      <Card>
        <CardHeader><CardTitle className="text-base">Основные настройки</CardTitle></CardHeader>
        <CardContent className="divide-y px-5">
          <SettingRow label="Язык интерфейса">
            <select className="text-sm bg-background text-foreground border border-input rounded-md px-2 py-1 h-8 focus:outline-none focus:ring-1 focus:ring-ring"
              value={lang} onChange={e => setLang(e.target.value)}>
              <option value="ru">Русский</option>
              <option value="en">English</option>
            </select>
          </SettingRow>
          <SettingRow label="Тема оформления">
            <div className="flex rounded-md border border-input overflow-hidden h-8">
              {[["light","Светлая"],["dark","Тёмная"],["system","Авто"]].map(([v, l]) => (
                <button key={v} onClick={() => setTheme(v)}
                  className={cn("px-3 text-xs transition-colors border-r last:border-r-0 border-input",
                    theme === v ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:bg-muted")}>
                  {l}
                </button>
              ))}
            </div>
          </SettingRow>
          <SettingRow label="Часовой пояс">
            <select className="text-sm bg-background text-foreground border border-input rounded-md px-2 py-1 h-8 focus:outline-none focus:ring-1 focus:ring-ring"
              value={timezone} onChange={e => setTimezone(e.target.value)}>
              {["Europe/Moscow","Europe/Berlin","Europe/Amsterdam","Asia/Singapore","UTC"].map(z => (
                <option key={z} value={z}>{z}</option>
              ))}
            </select>
          </SettingRow>
          <SettingRow label="Интервал автообновления (сек)"
            description="Как часто страницы обновляют данные">
            <Input className="w-20 h-8 text-sm" value={refreshSec} onChange={e => setRefreshSec(e.target.value)} />
          </SettingRow>
          <SettingRow label="Таймаут диагностики (сек)"
            description="Максимальное время ожидания при probe-тестах">
            <Input className="w-20 h-8 text-sm" value={probeTimeout} onChange={e => setProbeTimeout(e.target.value)} />
          </SettingRow>
        </CardContent>
      </Card>

      <Card>
        <CardHeader>
          <CardTitle className="text-base">База данных приложения</CardTitle>
          <CardDescription className="text-xs">
            Резервная копия SQLite бекенда: серверы, мониторинг, оповещения, EvoBGP. На время операции планировщик
            сбора данных приостанавливается.
          </CardDescription>
        </CardHeader>
        <CardContent className="divide-y px-5">
          {!systemDbAvailable && (
            <div className="flex items-start gap-2 py-3 text-xs text-amber-600 dark:text-amber-400">
              <AlertCircleIcon className="size-3.5 mt-0.5 shrink-0" />
              <span>Доступно только в live-режиме при доступном бекенде.</span>
            </div>
          )}
          <SettingRow
            label="Скачать бэкап"
            description="Консистентная копия файла mikrotik.db"
          >
            <Button
              variant="outline"
              size="sm"
              className="h-8"
              disabled={!systemDbAvailable || dbBackupBusy || dbRestoreBusy}
              onClick={() => { void handleSystemDatabaseBackup() }}
            >
              {dbBackupBusy ? <LoaderCircleIcon className="size-4 animate-spin" /> : <DownloadIcon className="size-4" />}
              {dbBackupBusy ? "Подготовка…" : "Скачать"}
            </Button>
          </SettingRow>
          <SettingRow
            label="Восстановить из файла"
            description="Полностью заменяет текущую базу SQLite"
          >
            <div className="flex flex-col items-end gap-2">
              <Input
                ref={dbRestoreInputRef}
                type="file"
                accept=".db,.sqlite,.sqlite3,application/octet-stream"
                className="hidden"
                disabled={!systemDbAvailable || dbBackupBusy || dbRestoreBusy}
                onChange={(e) => {
                  const file = e.target.files?.[0] ?? null
                  if (!file) return
                  setDbRestoreFile(file)
                }}
              />
              <div className="flex items-center gap-2">
                <Button
                  variant="outline"
                  size="sm"
                  className="h-8"
                  disabled={!systemDbAvailable || dbBackupBusy || dbRestoreBusy}
                  onClick={() => dbRestoreInputRef.current?.click()}
                >
                  <UploadIcon className="size-4" />
                  Выбрать файл
                </Button>
              </div>
              {dbRestoreFile && (
                <p className="text-xs text-muted-foreground max-w-[220px] text-right break-all">{dbRestoreFile.name}</p>
              )}
            </div>
          </SettingRow>
        </CardContent>
      </Card>

      <Card id="route-ai" className="scroll-mt-4">
        <CardHeader>
          <CardTitle className="text-base">Route AI</CardTitle>
          <CardDescription className="text-xs">
            Параметры оптимизации маршрутов по умолчанию (тот же набор, что на странице «Оптимизатор маршрутов»). Пороги и
            веса настраиваются в инструменте, не через отдельный API.
          </CardDescription>
        </CardHeader>
        <CardContent className="space-y-4 px-5 pb-5">
          <dl className="grid grid-cols-1 sm:grid-cols-2 gap-x-8 gap-y-2 text-xs">
            <div className="flex justify-between gap-4 border-b border-border/50 py-1.5">
              <dt className="text-muted-foreground">Мин. выигрыш (переключение)</dt>
              <dd className="font-mono tabular-nums">{ra.switchThreshold}%</dd>
            </div>
            <div className="flex justify-between gap-4 border-b border-border/50 py-1.5">
              <dt className="text-muted-foreground">Гистерезис</dt>
              <dd className="font-mono tabular-nums">{ra.hysteresisThreshold}%</dd>
            </div>
            <div className="flex justify-between gap-4 border-b border-border/50 py-1.5">
              <dt className="text-muted-foreground">Вес задержки (ping)</dt>
              <dd className="font-mono tabular-nums">{ra.pingWeight}%</dd>
            </div>
            <div className="flex justify-between gap-4 border-b border-border/50 py-1.5">
              <dt className="text-muted-foreground">Интервал зондирования</dt>
              <dd className="font-mono tabular-nums">{ra.probeIntervalMin} мин</dd>
            </div>
            <div className="flex justify-between gap-4 border-b border-border/50 py-1.5 sm:col-span-2">
              <dt className="text-muted-foreground">Автоприменение</dt>
              <dd>{ra.autoApply ? `да, каждые ${ra.autoApplyIntervalMin} мин` : "нет"}</dd>
            </div>
          </dl>
          <Link
            href="/route-optimizer"
            className={cn(buttonVariants({ variant: "outline", size: "sm" }), "h-8")}
          >
            Открыть оптимизатор маршрутов
          </Link>
        </CardContent>
      </Card>

      </div>
    )

    // ── EvoBGP ──
    if (section === "EvoBGP") return (
      <div className="space-y-4">
        {(mode !== "live" || backendStatus !== true) && (
          <Card>
            <CardContent className="pt-4 pb-4 px-4">
              <p className="text-sm font-medium">Интеграция доступна в live-режиме</p>
              <p className="text-xs text-muted-foreground mt-1">
                Включите «Живые» данные и убедитесь, что локальный бекенд доступен (раздел «Общие»).
              </p>
            </CardContent>
          </Card>
        )}

        <Card>
          <CardHeader>
            <CardTitle className="text-base">EvoBGP API</CardTitle>
            <CardDescription className="text-xs">
              Control plane EvoBGP: Bearer-ключ и роль viewer+ — см.{" "}
              <a
                className="underline underline-offset-2"
                href="https://git.shts.su/denozord/EvoBGP/src/branch/main/docs/access.md"
                target="_blank"
                rel="noreferrer"
              >
                access.md
              </a>
              . URL и ключ хранятся в SQLite на сервере бекенда (
              <code className="font-mono bg-muted px-1 rounded">evobgp_settings</code>
              ). Каталог —{" "}
              <code className="font-mono bg-muted px-1 rounded">GET /v1/router-lists/catalog</code> через прокси.
            </CardDescription>
          </CardHeader>
          <CardContent className="divide-y px-5 space-y-4 pb-5">
            <SettingRow
              label="Базовый URL API"
              description="Например http://control.example:8080 — без суффикса /v1"
            >
              <Input
                className="w-full max-w-md h-8 text-sm font-mono"
                value={evoBaseDraft}
                onChange={(e) => setEvoBaseDraft(e.target.value)}
                placeholder="http://localhost:8080"
                disabled={mode !== "live" || backendStatus !== true || evoSaveBusy}
              />
            </SettingRow>
            <SettingRow
              label="API-ключ"
              description={
                evo.secretConfigured
                  ? "В БД уже есть ключ — введите новый только для замены"
                  : "Сохраняется общей кнопкой «Сохранить» в шапке страницы"
              }
            >
              <div className="flex items-center gap-2">
                <Input
                  className="w-full max-w-md h-8 text-sm font-mono"
                  type={showEvoKey ? "text" : "password"}
                  autoComplete="off"
                  value={evoKeyDraft}
                  onChange={(e) => setEvoKeyDraft(e.target.value)}
                  placeholder={evo.secretConfigured ? "Оставьте пустым, чтобы не менять" : "Bearer-токен"}
                  disabled={mode !== "live" || backendStatus !== true || evoSaveBusy}
                />
                <Button
                  type="button"
                  variant="outline"
                  size="sm"
                  className="h-8 shrink-0"
                  onClick={() => setShowEvoKey((v) => !v)}
                >
                  {showEvoKey ? <EyeOffIcon className="size-3.5" /> : <EyeIcon className="size-3.5" />}
                </Button>
              </div>
            </SettingRow>
            <SettingRow
              label="Подставлять данные EvoBGP"
              description="На страницах Домены, IP-диапазоны, ASN и Communities вместо моков из lib/data"
            >
              <Toggle
                checked={evoEnabledDraft}
                onChange={(v) => setEvoEnabledDraft(v)}
              />
            </SettingRow>
            <div className="flex flex-wrap items-center gap-2 pt-2">
              <Button
                type="button"
                variant="outline"
                size="sm"
                className="h-8 text-destructive border-destructive/40 hover:bg-destructive/10"
                disabled={mode !== "live" || backendStatus !== true || evoSaveBusy || !evo.secretConfigured}
                onClick={async () => {
                  setEvoSaveBusy(true)
                  setEvoSaveErr(null)
                  try {
                    await evo.saveSettings({ apiKey: null })
                    setEvoKeyDraft("")
                    markSaved()
                  } catch (e) {
                    setEvoSaveErr(e instanceof Error ? e.message : "Ошибка")
                  } finally {
                    setEvoSaveBusy(false)
                  }
                }}
              >
                Удалить ключ из БД
              </Button>
            </div>
            {evoSaveErr && <p className="text-xs text-destructive">{evoSaveErr}</p>}
            <p className="text-[11px] text-muted-foreground">
              «Проверить ключ» использует поля формы; незаполненное поле подставляется из БД. «Обновить каталог» — только по сохранённым в БД настройкам.
            </p>
            <div className="flex flex-wrap items-center gap-2 pt-1">
              <Button
                type="button"
                variant="outline"
                size="sm"
                className="h-8"
                disabled={
                  mode !== "live" ||
                  backendStatus !== true ||
                  evoBusy !== null ||
                  evoSaveBusy ||
                  !(
                    (evoBaseDraft.trim() || evo.baseUrl.trim()) &&
                    (evoKeyDraft.trim() || evo.secretConfigured)
                  )
                }
                onClick={async () => {
                  setEvoBusy("test")
                  setEvoTestResult(null)
                  const b = evoBaseDraft.trim()
                  const k = evoKeyDraft.trim()
                  let draft: EvoBgpTestDraft | undefined
                  if (b || k) {
                    draft = {}
                    if (b) draft.baseUrl = b
                    if (k) draft.apiKey = k
                  }
                  const r = await evo.testConnection(draft)
                  setEvoTestResult({ ok: r.ok, message: r.message })
                  setEvoBusy(null)
                }}
              >
                {evoBusy === "test" ? <RefreshCwIcon className="size-3.5 animate-spin" /> : null}
                Проверить ключ
              </Button>
              <Button
                type="button"
                variant="outline"
                size="sm"
                className="h-8"
                disabled={mode !== "live" || backendStatus !== true || evoBusy !== null || evoSaveBusy || !evo.enabled}
                onClick={async () => {
                  setEvoBusy("refresh")
                  await evo.refresh()
                  setEvoBusy(null)
                }}
              >
                {evoBusy === "refresh" || evo.loading ? <RefreshCwIcon className="size-3.5 animate-spin" /> : null}
                Обновить каталог
              </Button>
              {evo.snapshot?.fetchedAt && (
                <span className="text-xs text-muted-foreground">
                  Загружено: {new Date(evo.snapshot.fetchedAt).toLocaleString("ru-RU")}
                </span>
              )}
            </div>
            {evoTestResult && (
              <p className={cn(
                "text-xs",
                evoTestResult.ok ? "text-emerald-600 dark:text-emerald-400" : "text-destructive",
              )}>
                {evoTestResult.message}
              </p>
            )}
            {evo.error && (
              <p className="text-xs text-destructive">{evo.error}</p>
            )}
          </CardContent>
        </Card>
      </div>
    )

    // ── Уведомления ──
    if (section === "Уведомления") return (
      <div className="space-y-4">
        <Card>
          <CardHeader><CardTitle className="text-base">Каналы уведомлений</CardTitle></CardHeader>
          <CardContent className="divide-y px-5">
            <SettingRow label="Email" description="Отправка уведомлений на admin@routerlists.io">
              <Toggle checked={notifEmail} onChange={setNotifEmail} />
            </SettingRow>
            {notifEmail && <div className="py-3"><Input className="text-sm h-8" defaultValue="admin@routerlists.io" /></div>}
            <SettingRow label="Slack" description="Webhook-интеграция с каналом #alerts">
              <Toggle checked={notifSlack} onChange={setNotifSlack} />
            </SettingRow>
            {notifSlack && <div className="py-3"><Input className="text-sm h-8 font-mono" placeholder="https://hooks.slack.com/…" /></div>}
            <SettingRow label="Webhook" description="POST-запрос на произвольный endpoint">
              <Toggle checked={notifWh} onChange={setNotifWh} />
            </SettingRow>
            {notifWh && <div className="py-3"><Input className="text-sm h-8 font-mono" defaultValue="https://hooks.example.com/routerlists" /></div>}
          </CardContent>
        </Card>
        <Card>
          <CardHeader><CardTitle className="text-base">Триггеры</CardTitle></CardHeader>
          <CardContent className="divide-y px-5">
            <SettingRow label="Деградация узла" description="Потери пакетов > 5% или RTT > 100мс">
              <Toggle checked={notifDegr} onChange={setNotifDegr} />
            </SettingRow>
            <SettingRow label="Узел ушёл offline">
              <Toggle checked={notifOffline} onChange={setNotifOffline} />
            </SettingRow>
            <SettingRow label="Падение BGP-сессии">
              <Toggle checked={notifBgp} onChange={setNotifBgp} />
            </SettingRow>
            <SettingRow label="Просроченный бэкап" description="Если последний бэкап старше 2 дней">
              <Toggle checked={notifBackup} onChange={setNotifBackup} />
            </SettingRow>
          </CardContent>
        </Card>
      </div>
    )

    // ── Пользователи ──
    if (section === "Пользователи") return (
      <div className="flex flex-col gap-4">
        <div className="flex items-center justify-between gap-3">
          <p className="text-xs text-muted-foreground">
            {users.length} пользователей · {users.filter(u => u.active).length} активных
            {totalSubUsers > 0 && ` · ${totalSubUsers} GRE-клиентов`}
          </p>
          <Button size="sm" onClick={() => { setEditUser(null); setSheetOpen(true) }}>
            <PlusIcon className="size-4" />Пригласить
          </Button>
        </div>

        <Card className="overflow-hidden gap-0 py-0">
          {/* table header */}
          <div className="grid grid-cols-[1fr_120px_100px_80px_auto] items-center gap-3 px-4 py-2 border-b bg-muted/30 text-[11px] font-medium text-muted-foreground">
            <span>Пользователь</span>
            <span>Роль</span>
            <span>Последний вход</span>
            <span>Статус</span>
            <span />
          </div>

          <div className="divide-y divide-border/60">
            {users.map(u => {
              return (
                <div key={u.id} className="grid grid-cols-[1fr_120px_100px_80px_auto] items-center gap-3 px-4 py-2.5 hover:bg-muted/20 transition-colors">
                  {/* user */}
                  <div className="flex items-center gap-2.5 min-w-0">
                    <AvatarCircle avatar={u.avatar} active={u.active} />
                    <div className="min-w-0">
                      <p className="text-sm font-medium truncate">{u.name}</p>
                      <div className="flex items-center gap-2 mt-0.5">
                        <p className="text-[11px] font-mono text-muted-foreground">@{u.login}</p>
                        {u.subUsers.length > 0 && (
                          <span className="inline-flex items-center gap-0.5 text-[10px] text-muted-foreground/60">
                            <CableIcon className="size-2.5" />{u.subUsers.length}
                          </span>
                        )}
                      </div>
                    </div>
                  </div>
                  {/* role */}
                  <span className={cn("text-[11px] font-medium px-2 py-0.5 rounded-full w-fit", ROLE_COLOR[u.role])}>
                    {ROLE_LABEL[u.role]}
                  </span>
                  {/* last */}
                  <span className="text-xs text-muted-foreground">{u.last}</span>
                  {/* status */}
                  <span className={cn("text-[11px] font-medium", u.active ? "text-emerald-600 dark:text-emerald-400" : "text-muted-foreground")}>
                    {u.active ? "Активен" : "Заблокирован"}
                  </span>
                  {/* actions */}
                  <div className="flex items-center gap-0.5 justify-end">
                    <Button size="sm" variant="ghost" className="size-7 p-0 text-muted-foreground hover:text-foreground"
                      onClick={() => { setEditUser(u); setSheetOpen(true) }} title="Редактировать">
                      <PencilIcon className="size-3.5" />
                    </Button>
                    {u.id !== "u1" && (
                      <Button size="sm" variant="ghost" className="size-7 p-0 text-muted-foreground hover:text-destructive"
                        onClick={() => setDeleteTarget(u)} title="Удалить">
                        <TrashIcon className="size-3.5" />
                      </Button>
                    )}
                  </div>
                </div>
              )
            })}
          </div>
        </Card>

        {/* access summary */}
        <Card className="overflow-hidden gap-0 py-0">
          <div className="flex items-center gap-3 px-4 py-3 border-b">
            <UserIcon className="size-4 text-muted-foreground shrink-0" />
            <span className="text-sm font-medium">Сводка прав доступа</span>
          </div>
          <div className="overflow-x-auto">
            <table className="w-full text-sm">
              <thead>
                <tr className="border-b text-[11px] text-muted-foreground bg-muted/30">
                  <th className="text-left font-medium px-4 py-2">Пользователь</th>
                  <th className="text-left font-medium px-4 py-2">Разделы</th>
                  <th className="text-left font-medium px-4 py-2">Серверы</th>
                  <th className="text-left font-medium px-4 py-2">Права записи</th>
                </tr>
              </thead>
              <tbody className="divide-y divide-border/60">
                {users.map(u => {
                  const writeSections = u.role === "admin" ? ALL_SECTIONS : u.sections.filter(s => s.level === "write").map(s => s.section)
                  const readSections  = u.role === "admin" ? [] : u.sections.filter(s => s.level === "read").map(s => s.section)
                  const accessServers = u.role === "admin" ? servers : servers.filter(s => u.servers.find(p => p.serverId === s.id && p.level !== "none"))
                  return (
                    <tr key={u.id} className="hover:bg-muted/20 transition-colors">
                      <td className="px-4 py-2.5">
                        <div className="flex items-center gap-2">
                          <AvatarCircle avatar={u.avatar} active={u.active} />
                          <span className="text-sm font-medium">{u.name}</span>
                        </div>
                      </td>
                      <td className="px-4 py-2.5 text-xs text-muted-foreground">
                        {u.role === "admin"
                          ? <span className="text-violet-600 dark:text-violet-400 font-medium">Все ({ALL_SECTIONS.length})</span>
                          : <span>{(readSections.length + writeSections.length)} из {ALL_SECTIONS.length}</span>}
                      </td>
                      <td className="px-4 py-2.5 text-xs text-muted-foreground">
                        {u.role === "admin"
                          ? <span className="text-violet-600 dark:text-violet-400 font-medium">Все ({servers.length})</span>
                          : <span>{accessServers.length} из {servers.length}</span>}
                      </td>
                      <td className="px-4 py-2.5">
                        <div className="flex flex-wrap gap-1">
                          {u.role === "admin"
                            ? <span className="text-[10px] px-1.5 py-0.5 rounded bg-violet-500/10 text-violet-600 dark:text-violet-400 border border-violet-500/20">Полный доступ</span>
                            : writeSections.length === 0
                              ? <span className="text-[10px] text-muted-foreground">Только просмотр</span>
                              : writeSections.slice(0, 3).map(s => (
                                  <span key={s} className="text-[10px] px-1.5 py-0.5 rounded bg-emerald-500/10 text-emerald-600 dark:text-emerald-400 border border-emerald-500/20">{s}</span>
                                ))
                          }
                          {u.role !== "admin" && writeSections.length > 3 && (
                            <span className="text-[10px] text-muted-foreground">+{writeSections.length - 3}</span>
                          )}
                        </div>
                      </td>
                    </tr>
                  )
                })}
              </tbody>
            </table>
          </div>
        </Card>
      </div>
    )

    // ── API-ключи ──
    if (section === "API-ключи") return (
      <div className="space-y-4">
        <div className="flex justify-end">
          <Button size="sm"><PlusIcon className="size-4" />Создать ключ</Button>
        </div>
        <div className="space-y-3">
          {apiKeys.map(k => (
            <Card key={k.id}>
              <CardContent className="pt-4 pb-3 px-4">
                <div className="flex items-start justify-between gap-4">
                  <div className="min-w-0">
                    <p className="text-sm font-medium">{k.name}</p>
                    <div className="flex items-center gap-2 mt-1">
                      <code className="text-xs font-mono text-muted-foreground bg-muted px-1.5 py-0.5 rounded">{k.prefix}</code>
                      <button onClick={() => handleCopy(k.prefix)} className="text-muted-foreground/40 hover:text-muted-foreground transition-colors">
                        {copied === k.prefix ? <CheckIcon className="size-3" /> : <CopyIcon className="size-3" />}
                      </button>
                    </div>
                    <div className="flex flex-wrap gap-1 mt-2">
                      {k.scopes.map(s => (
                        <span key={s} className="text-[10px] font-mono bg-muted px-1.5 py-0.5 rounded text-muted-foreground">{s}</span>
                      ))}
                    </div>
                  </div>
                  <div className="text-right shrink-0">
                    <p className="text-xs text-muted-foreground">Создан: {k.created}</p>
                    <p className="text-xs text-muted-foreground mt-0.5">Использован: {k.last}</p>
                    <div className="flex gap-1 justify-end mt-2">
                      <Button size="sm" variant="ghost" className="h-7 px-2 text-xs">Переиздать</Button>
                      <Button size="sm" variant="ghost" className="size-7 p-0 text-destructive hover:text-destructive"
                        onClick={() => setApiKeys(p => p.filter(x => x.id !== k.id))}>
                        <TrashIcon className="size-3.5" />
                      </Button>
                    </div>
                  </div>
                </div>
              </CardContent>
            </Card>
          ))}
        </div>
        <Card>
          <CardHeader>
            <CardTitle className="text-sm">Документация API</CardTitle>
            <CardDescription className="text-xs">Base URL: https://api.routerlists.io/v1</CardDescription>
          </CardHeader>
          <CardContent className="px-4 pb-4">
            <div className="grid grid-cols-2 gap-2 text-xs">
              {[
                ["GET",  "/servers",    "Список серверов"],
                ["GET",  "/traffic",    "Данные трафика"],
                ["GET",  "/filters",    "Фильтры маршрутов"],
                ["POST", "/filters",    "Создать фильтр"],
                ["GET",  "/probes",     "Диагностические пробы"],
                ["POST", "/probes/run", "Запустить тест"],
              ].map(([method, path, desc], i) => (
                <div key={`${method}-${path}-${i}`} className="flex items-baseline gap-2">
                  <span className={cn("font-mono text-[10px] font-bold w-8 shrink-0",
                    method === "GET" ? "text-emerald-500" : "text-sky-500")}>{method}</span>
                  <code className="font-mono text-muted-foreground">{path}</code>
                  <span className="text-muted-foreground/60 text-[10px]">{desc}</span>
                </div>
              ))}
            </div>
          </CardContent>
        </Card>
      </div>
    )

    // ── Безопасность ──
    if (section === "Безопасность") return (
      <div className="space-y-4">
        <Card>
          <CardHeader><CardTitle className="text-base">Аутентификация</CardTitle></CardHeader>
          <CardContent className="divide-y px-5">
            <SettingRow label="Двухфакторная аутентификация (MFA)"
              description="TOTP / Authenticator app для всех администраторов">
              <Toggle checked={mfa} onChange={setMfa} />
            </SettingRow>
            <SettingRow label="Тайм-аут сессии (мин)" description="Автоматический выход при бездействии">
              <Input className="w-20 h-8 text-sm" value={sessMin} onChange={e => setSessMin(e.target.value)} />
            </SettingRow>
          </CardContent>
        </Card>
        <Card>
          <CardHeader>
            <CardTitle className="text-base">Allowlist IP-адресов</CardTitle>
            <CardDescription className="text-xs">Доступ разрешён только с этих сетей. Одна запись на строку.</CardDescription>
          </CardHeader>
          <CardContent className="px-4 pb-4">
            <textarea value={ipAllow} onChange={e => setIpAllow(e.target.value)} rows={4}
              className="w-full rounded-md border bg-muted px-3 py-2 text-xs font-mono resize-none outline-none focus:ring-1 focus:ring-ring" />
          </CardContent>
        </Card>
        <Card>
          <CardHeader><CardTitle className="text-base">Аудит</CardTitle></CardHeader>
          <CardContent className="divide-y px-5">
            <SettingRow label="Расширенный журнал аудита"
              description="Записывать все изменения конфигурации с указанием пользователя и IP">
              <Toggle checked={auditLog} onChange={setAuditLog} />
            </SettingRow>
          </CardContent>
        </Card>
        <Card>
          <CardHeader><CardTitle className="text-base text-destructive">Опасная зона</CardTitle></CardHeader>
          <CardContent className="px-4 pb-4">
            <div className="flex items-center justify-between">
              <div>
                <p className="text-sm font-medium">Сбросить все настройки</p>
                <p className="text-xs text-muted-foreground">Удалит пользовательские параметры и вернёт заводские значения</p>
              </div>
              <Button variant="outline" size="sm" className="border-destructive text-destructive hover:bg-destructive hover:text-destructive-foreground">
                Сбросить
              </Button>
            </div>
          </CardContent>
        </Card>
      </div>
    )
  }

  return (
    <div className="flex flex-col h-full">
      <PageHeader
        crumbs={[{ label: "Система" }, { label: "Настройки" }]}
        actions={
          <Button
            size="sm"
            onClick={() => { void handleSave() }}
            disabled={
              section === "EvoBGP" &&
              (evoSaveBusy || mode !== "live" || backendStatus !== true)
            }
          >
            {section === "EvoBGP" && evoSaveBusy ? (
              <LoaderCircleIcon className="size-4 animate-spin" />
            ) : saved ? (
              <CheckIcon className="size-4" />
            ) : (
              <SaveIcon className="size-4" />
            )}
            {section === "EvoBGP" && evoSaveBusy
              ? "Сохранение…"
              : saved
                ? "Сохранено!"
                : "Сохранить"}
          </Button>
        }
      />

      <div className="flex-1 overflow-y-auto p-6">
        <div className="max-w-[960px] mx-auto grid grid-cols-[180px_1fr] gap-6">

          {/* nav */}
          <nav className="flex flex-col gap-1 self-start sticky top-0">
            {SECTIONS_NAV.map(s => (
              <button key={s} onClick={() => setSection(s)}
                className={cn(
                  "text-left px-3 py-2 rounded-md text-sm transition-colors",
                  s === section ? "bg-primary text-primary-foreground font-medium" : "hover:bg-muted text-muted-foreground hover:text-foreground",
                )}>
                {s}
              </button>
            ))}
          </nav>

          {/* content */}
          <div className="min-w-0">{renderContent()}</div>
        </div>
      </div>

      {/* user sheet */}
      <UserSheet
        key={sheetOpen ? (editUser?.id ?? "create") : "closed"}
        open={sheetOpen}
        user={editUser}
        onSave={handleUserSave}
        onClose={() => setSheetOpen(false)}
      />

      {/* delete confirm */}
      {dbRestoreFile && (
        <DatabaseRestoreConfirm
          filename={dbRestoreFile.name}
          busy={dbRestoreBusy}
          onConfirm={() => { void handleSystemDatabaseRestoreConfirm() }}
          onCancel={() => {
            if (dbRestoreBusy) return
            setDbRestoreFile(null)
            if (dbRestoreInputRef.current) dbRestoreInputRef.current.value = ""
          }}
        />
      )}
      {deleteTarget && (
        <DeleteConfirm
          user={deleteTarget}
          onConfirm={() => { setUsers(p => p.filter(u => u.id !== deleteTarget.id)); setDeleteTarget(null) }}
          onCancel={() => setDeleteTarget(null)}
        />
      )}
    </div>
  )
}
