"use client"

import { useEffect, useMemo, useState, type ReactNode } from "react"
import { FormField, FormToggle, SegmentedControl } from "@/components/form-kit"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import {
  Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle,
} from "@/components/ui/sheet"
import {
  Stepper,
  StepperContent,
  StepperIndicator,
  StepperItem,
  StepperNav,
  StepperPanel,
  StepperSeparator,
  StepperTitle,
  StepperTrigger,
} from "@/components/reui/stepper"
import { Badge } from "@/components/reui/badge"
import { IconTile } from "@/components/reui/icon-tile"
import { Frame, FramePanel } from "@/components/reui/frame"
import {
  Item,
  ItemActions,
  ItemContent,
  ItemMedia,
  ItemTitle,
} from "@/components/ui/item"
import { Flag } from "@/components/flag"
import { StatusDot } from "@/components/status-dot"
import { cn } from "@/lib/utils"
import { listInterfaceCatalog } from "@/shared/api/users"
import { TYPE_VARIANT } from "@/components/data-grids/users-expanded-detail"
import {
  bindingDiffKey,
  bindingTitle,
  catalogForServer,
  defaultSections,
  defaultServers,
  IFACE_TYPE_LABEL,
  PERM_COLOR,
  PERM_OPTS,
  ROLE_LABEL,
  SECTION_GROUP_DEFS,
  type AppUser,
  type AppUserForm,
  type CatalogIface,
  type InterfaceBinding,
  type InterfaceType,
  type PermLevel,
  type Role,
  type UserServerOption,
} from "@/lib/users"
import {
  CableIcon, ChevronDownIcon, EyeIcon, KeyRoundIcon, LayoutDashboardIcon,
  NetworkIcon, PlusIcon, ServerIcon, ShieldIcon, TrashIcon, WrenchIcon,
} from "lucide-react"

const IFACE_TILE: Record<InterfaceType, { icon: typeof CableIcon; className: string }> = {
  ether: { icon: CableIcon, className: "text-muted-foreground" },
  gre: { icon: NetworkIcon, className: "text-info" },
  wg: { icon: ShieldIcon, className: "text-success" },
  other: { icon: CableIcon, className: "text-muted-foreground" },
}

type CatalogPick = {
  interfaceName: string
  peerPublicKey: string
  peerName?: string
  type: InterfaceType
}

function pickKey(p: CatalogPick): string {
  return `${p.interfaceName}\0${p.peerPublicKey}`
}

const SECTION_GROUP_ICONS: Record<string, ReactNode> = {
  "Обзор": <LayoutDashboardIcon className="size-3" />,
  "Данные": <EyeIcon className="size-3" />,
  "Управление": <WrenchIcon className="size-3" />,
  "Инструменты": <ShieldIcon className="size-3" />,
  "Система": <ServerIcon className="size-3" />,
}

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-success text-white"
              : o.v === "read" ? "bg-info text-white"
              : "bg-muted-foreground/70 text-white"
              : "text-muted-foreground hover:bg-muted",
          )}
        >
          {o.label}
        </button>
      ))}
    </div>
  )
}

function emptyForm(serverList: UserServerOption[]): AppUserForm {
  return {
    name: "", login: "", email: "", role: "viewer", active: true,
    sections: defaultSections("viewer"),
    servers: defaultServers("viewer", serverList),
    bindings: [],
  }
}

function toForm(user: AppUser): AppUserForm {
  return {
    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 })),
    bindings: user.bindings.map((b) => ({ ...b })),
  }
}

function isValidEmail(value: string) {
  const email = value.trim()
  return email.length > 0 && email.includes("@")
}

interface UserSheetProps {
  open: boolean
  user: AppUser | null
  users: AppUser[]
  servers: UserServerOption[]
  isLive: boolean
  backendUrl: string
  saving?: boolean
  onSave: (form: AppUserForm) => void
  onClose: () => void
}

function UserSheet({
  open, user, users, servers, isLive, backendUrl, saving, onSave, onClose,
}: UserSheetProps) {
  const isCreate = user === null
  const [sheetStep, setSheetStep] = useState(1)
  const [form, setForm] = useState<AppUserForm>(() => (user ? toForm(user) : emptyForm(servers)))
  const [errors, setErrors] = useState<Partial<Record<keyof AppUserForm, string>>>({})
  const [catalogServerId, setCatalogServerId] = useState(servers[0]?.id ?? "")
  const [catalog, setCatalog] = useState<CatalogIface[]>([])
  const [selectedPicks, setSelectedPicks] = useState<CatalogPick[]>([])
  const [expandedWg, setExpandedWg] = useState<string | null>(null)
  const [newComment, setNewComment] = useState("")

  useEffect(() => {
    if (!open) return
    setForm(user ? toForm(user) : emptyForm(servers))
    setSheetStep(1)
    setErrors({})
    setCatalogServerId(servers[0]?.id ?? "")
    setSelectedPicks([])
    setExpandedWg(null)
    setNewComment("")
  }, [open, user, servers])

  useEffect(() => {
    if (!open || !catalogServerId) {
      setCatalog([])
      return
    }
    if (!isLive) {
      const occupancy = users.map((u) =>
        u.id === user?.id ? { ...u, bindings: form.bindings } : u,
      )
      const withDraft = user
        ? occupancy
        : [...occupancy, { id: "__draft__", name: "", login: "", email: "", role: "viewer" as const, last: "", avatar: "", active: true, sections: [], servers: [], bindings: form.bindings }]
      setCatalog(catalogForServer(catalogServerId, withDraft))
      return
    }
    let cancelled = false
    void listInterfaceCatalog(backendUrl, catalogServerId)
      .then((ifaces) => { if (!cancelled) setCatalog(ifaces) })
      .catch(() => { if (!cancelled) setCatalog([]) })
    return () => { cancelled = true }
  }, [open, catalogServerId, isLive, backendUrl, users, user, form.bindings])

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

  const setRole = (role: Role) => {
    setForm((f) => ({
      ...f,
      role,
      sections: defaultSections(role),
      servers: servers.map((s) => ({ serverId: s.id, level: role === "admin" ? "write" : "read" })),
    }))
  }

  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 submit = () => {
    const email = form.email.trim()
    const e: Partial<Record<keyof AppUserForm, string>> = {}
    if (!form.name.trim()) e.name = "Обязательное поле"
    if (!isValidEmail(email)) e.email = email ? "Укажите корректный email" : "Обязательное поле"
    setErrors(e)
    if (Object.keys(e).length) {
      setSheetStep(1)
      return
    }
    onSave({ ...form, email, login: email })
  }

  const isAdmin = form.role === "admin"
  const catalogSrv = servers.find((s) => s.id === catalogServerId)

  const addSelectedBindings = () => {
    if (!catalogSrv || selectedPicks.length === 0) return
    const existing = new Set(form.bindings.map(bindingDiffKey))
    const next: InterfaceBinding[] = [...form.bindings]
    for (const pick of selectedPicks) {
      const key = bindingDiffKey({
        serverId: catalogSrv.id,
        interfaceName: pick.interfaceName,
        peerPublicKey: pick.peerPublicKey,
      })
      if (existing.has(key)) continue
      next.push({
        id: `pending-${catalogSrv.id}-${pick.interfaceName}-${pick.peerPublicKey || "iface"}`,
        userId: user?.id ?? "",
        serverId: catalogSrv.id,
        serverName: catalogSrv.name,
        serverSite: catalogSrv.site,
        serverCountry: catalogSrv.country,
        interfaceName: pick.interfaceName,
        interfaceType: pick.type,
        peerPublicKey: pick.peerPublicKey || undefined,
        peerName: pick.peerName,
        comment: newComment.trim(),
      })
    }
    setForm((f) => ({ ...f, bindings: next }))
    setSelectedPicks([])
    setNewComment("")
  }

  const removeBinding = (id: string) => {
    setForm((f) => ({ ...f, bindings: f.bindings.filter((b) => b.id !== id) }))
  }

  const togglePick = (pick: CatalogPick) => {
    setSelectedPicks((prev) => {
      const key = pickKey(pick)
      return prev.some((p) => pickKey(p) === key)
        ? prev.filter((p) => pickKey(p) !== key)
        : [...prev, pick]
    })
  }

  const alreadyBoundHere = useMemo(
    () => new Set(
      form.bindings
        .filter((b) => b.serverId === catalogServerId)
        .map((b) => `${b.interfaceName}\0${b.peerPublicKey ?? ""}`),
    ),
    [form.bindings, catalogServerId],
  )

  const selectedPickKeys = useMemo(() => new Set(selectedPicks.map(pickKey)), [selectedPicks])

  return (
    <Sheet open={open} onOpenChange={(v) => { if (!v) onClose() }}>
      <SheetContent side="right" className="w-full sm:max-w-lg flex flex-col gap-0 p-0">
        <SheetHeader className="px-6 pt-6 pb-4 border-b shrink-0">
          <SheetTitle>{isCreate ? "Новый пользователь" : "Редактировать пользователя"}</SheetTitle>
          <SheetDescription>
            {isCreate ? "Профиль, права и привязка интерфейсов" : "Права доступа и привязка интерфейсов"}
          </SheetDescription>
        </SheetHeader>

        <Stepper value={sheetStep} onValueChange={setSheetStep} className="flex-1 flex flex-col min-h-0 px-6 py-5">
          <StepperNav className="mb-5">
            <StepperItem step={1}>
              <StepperTrigger>
                <StepperIndicator>1</StepperIndicator>
                <StepperTitle className="sr-only">Профиль</StepperTitle>
              </StepperTrigger>
              <StepperSeparator />
            </StepperItem>
            <StepperItem step={2}>
              <StepperTrigger>
                <StepperIndicator>2</StepperIndicator>
                <StepperTitle className="sr-only">Разделы</StepperTitle>
              </StepperTrigger>
              <StepperSeparator />
            </StepperItem>
            <StepperItem step={3}>
              <StepperTrigger>
                <StepperIndicator>3</StepperIndicator>
                <StepperTitle className="sr-only">Серверы</StepperTitle>
              </StepperTrigger>
              <StepperSeparator />
            </StepperItem>
            <StepperItem step={4}>
              <StepperTrigger>
                <StepperIndicator>4</StepperIndicator>
                <StepperTitle className="sr-only">Интерфейсы</StepperTitle>
              </StepperTrigger>
            </StepperItem>
          </StepperNav>
          <StepperPanel className="flex-1 overflow-y-auto">
            <StepperContent value={1} className="flex flex-col gap-4">
              <FormField label="Полное имя" required error={errors.name}>
                <Input value={form.name} onChange={(e) => setField("name", e.target.value)} placeholder="Иван Иванов" />
              </FormField>
              <FormField label="Email" required error={errors.email}>
                <Input
                  value={form.email}
                  onChange={(e) => setField("email", e.target.value)}
                  placeholder="i.ivanov@company.io"
                  type="email"
                />
              </FormField>
              <FormField label="Роль" required>
                <SegmentedControl
                  value={form.role}
                  onChange={setRole}
                  options={[
                    { value: "viewer", label: ROLE_LABEL.viewer },
                    { value: "operator", label: ROLE_LABEL.operator },
                    { value: "admin", label: ROLE_LABEL.admin },
                  ]}
                />
              </FormField>
              <div className="flex items-center justify-between">
                <span className="text-sm font-medium">Активна</span>
                <FormToggle checked={form.active} onChange={(v) => setField("active", v)} />
              </div>
            </StepperContent>

            <StepperContent value={2} className="flex flex-col">
              <div className="flex items-center gap-2 px-0 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-muted-foreground flex items-center gap-1">
                    <ShieldIcon className="size-3" />Администратор имеет полный доступ
                  </span>
                )}
              </div>
              {SECTION_GROUP_DEFS.map((group) => (
                <div key={group.group}>
                  <div className="flex items-center gap-2 py-1.5 bg-muted/20 border-b">
                    <span className="text-muted-foreground">{SECTION_GROUP_ICONS[group.group]}</span>
                    <span className="text-[10px] font-semibold uppercase tracking-widest text-muted-foreground">
                      {group.group}
                    </span>
                  </div>
                  <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 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>
              ))}
            </StepperContent>

            <StepperContent value={3} className="flex flex-col">
              <div className="flex items-center gap-2 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>
                ))}
              </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 py-2.5 hover:bg-muted/20 transition-colors">
                      <div className="flex items-center gap-2.5 min-w-0">
                        {srv.status ? <StatusDot status={srv.status} /> : null}
                        {srv.country ? <Flag code={srv.country} size={14} /> : null}
                        <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>
            </StepperContent>

            <StepperContent value={4} className="flex flex-col">
              <p className="text-[11px] text-muted-foreground py-2.5 border-b">
                Ethernet и GRE — целиком. WireGuard — только пир (public-key).
              </p>

              <div className="py-3 flex flex-col gap-3 border-b">
                <label className="text-[10px] text-muted-foreground">Сервер</label>
                <select
                  className="h-8 rounded-md border bg-background px-2 text-xs font-mono"
                  value={catalogServerId}
                  onChange={(e) => { setCatalogServerId(e.target.value); setSelectedPicks([]); setExpandedWg(null) }}
                >
                  {servers.map((s) => (
                    <option key={s.id} value={s.id}>{s.name} · {s.site}</option>
                  ))}
                </select>
                <Frame dense spacing="sm">
                  <FramePanel className="max-h-64 overflow-y-auto p-1.5">
                    {catalog.length === 0 && (
                      <p className="px-2 py-3 text-center text-[11px] text-muted-foreground">Нет интерфейсов в каталоге</p>
                    )}
                    <div className="flex flex-col gap-0.5">
                      {catalog.map((iface) => {
                        const tile = IFACE_TILE[iface.type]
                        const Icon = tile.icon
                        if (iface.type === "wg") {
                          const open = expandedWg === iface.name
                          const legacyTaken = Boolean(iface.boundUserId && iface.boundUserId !== user?.id)
                          const legacyMine = alreadyBoundHere.has(`${iface.name}\0`)
                          return (
                            <div key={iface.name} className="flex flex-col gap-0.5">
                              <Item
                                size="xs"
                                variant={open ? "muted" : "default"}
                                render={<button type="button" onClick={() => setExpandedWg(open ? null : iface.name)} />}
                                className="h-11 min-h-11 flex-nowrap rounded-md py-0"
                              >
                                <ItemMedia>
                                  <IconTile variant="elevated" className={cn("size-10.5 shrink-0", tile.className)}>
                                    <Icon />
                                  </IconTile>
                                </ItemMedia>
                                <ItemContent className="min-w-0">
                                  <ItemTitle className="max-w-full min-w-0 gap-1.5 font-mono text-[11px]">
                                    <span className="min-w-0 truncate">{iface.name}</span>
                                    <Badge variant={TYPE_VARIANT.wg} size="sm">WireGuard</Badge>
                                  </ItemTitle>
                                </ItemContent>
                                <ItemActions>
                                  {legacyMine ? (
                                    <Badge variant="warning-light" size="xs">весь интерфейс</Badge>
                                  ) : null}
                                  <ChevronDownIcon className={cn("size-3.5 text-muted-foreground transition-transform", open && "rotate-180")} />
                                </ItemActions>
                              </Item>
                              {open ? (
                                <div className="ml-4 flex flex-col gap-0.5 border-l pl-2">
                                  {iface.peersError ? (
                                    <p className="px-2 py-1.5 text-[11px] text-muted-foreground">Не удалось загрузить пиры</p>
                                  ) : null}
                                  {(iface.peers ?? []).length === 0 && !iface.peersError ? (
                                    <p className="px-2 py-1.5 text-[11px] text-muted-foreground">Нет пиров на интерфейсе</p>
                                  ) : null}
                                  {(iface.peers ?? []).map((peer) => {
                                    const pick: CatalogPick = {
                                      interfaceName: iface.name,
                                      peerPublicKey: peer.publicKey,
                                      peerName: peer.name,
                                      type: "wg",
                                    }
                                    const taken = Boolean(peer.boundUserId && peer.boundUserId !== user?.id)
                                    const mine = alreadyBoundHere.has(`${iface.name}\0${peer.publicKey}`)
                                    const disabled = taken || mine || legacyTaken
                                    const selected = selectedPickKeys.has(pickKey(pick))
                                    return (
                                      <Item
                                        key={peer.publicKey}
                                        size="xs"
                                        variant={selected ? "muted" : "default"}
                                        render={
                                          <button
                                            type="button"
                                            disabled={disabled}
                                            onClick={() => togglePick(pick)}
                                          />
                                        }
                                        className={cn(
                                          "h-11 min-h-11 flex-nowrap rounded-md py-0",
                                          selected && "ring-1 ring-border",
                                          disabled && "cursor-not-allowed opacity-50",
                                        )}
                                      >
                                        <ItemMedia>
                                          <IconTile variant="elevated" className="size-10.5 shrink-0 text-success">
                                            <KeyRoundIcon />
                                          </IconTile>
                                        </ItemMedia>
                                        <ItemContent className="min-w-0">
                                          <ItemTitle className="max-w-full min-w-0 gap-1.5 font-mono text-[11px]">
                                            <span className="min-w-0 truncate">{peer.name || peer.publicKey}</span>
                                            {peer.latestHandshake ? (
                                              <Badge variant="success-light" size="xs">handshake</Badge>
                                            ) : null}
                                          </ItemTitle>
                                        </ItemContent>
                                        <ItemActions>
                                          {taken ? (
                                            <span className="max-w-28 truncate text-[10px] text-muted-foreground">{peer.boundUserLogin}</span>
                                          ) : mine ? (
                                            <span className="text-[10px] text-muted-foreground">уже привязан</span>
                                          ) : selected ? (
                                            <Badge variant="secondary" size="xs">Выбран</Badge>
                                          ) : null}
                                        </ItemActions>
                                      </Item>
                                    )
                                  })}
                                </div>
                              ) : null}
                            </div>
                          )
                        }

                        const pick: CatalogPick = { interfaceName: iface.name, peerPublicKey: "", type: iface.type }
                        const taken = Boolean(iface.boundUserId && iface.boundUserId !== user?.id)
                        const mine = alreadyBoundHere.has(`${iface.name}\0`)
                        const disabled = taken || mine
                        const selected = selectedPickKeys.has(pickKey(pick))
                        return (
                          <Item
                            key={iface.name}
                            size="xs"
                            variant={selected ? "muted" : "default"}
                            render={
                              <button
                                type="button"
                                disabled={disabled}
                                onClick={() => togglePick(pick)}
                              />
                            }
                            className={cn(
                              "h-11 min-h-11 flex-nowrap rounded-md py-0",
                              selected && "ring-1 ring-border",
                              disabled && "cursor-not-allowed opacity-50",
                            )}
                          >
                            <ItemMedia>
                              <IconTile variant="elevated" className={cn("size-10.5 shrink-0", tile.className)}>
                                <Icon />
                              </IconTile>
                            </ItemMedia>
                            <ItemContent className="min-w-0">
                              <ItemTitle className="max-w-full min-w-0 gap-1.5 font-mono text-[11px]">
                                {iface.running ? <StatusDot status="online" /> : <StatusDot status="offline" />}
                                <span className="min-w-0 truncate">{iface.name}</span>
                                <Badge variant={TYPE_VARIANT[iface.type]} size="sm">
                                  {IFACE_TYPE_LABEL[iface.type]}
                                </Badge>
                              </ItemTitle>
                            </ItemContent>
                            <ItemActions>
                              {taken ? (
                                <span className="max-w-28 truncate text-[10px] text-muted-foreground">{iface.boundUserLogin}</span>
                              ) : mine ? (
                                <span className="text-[10px] text-muted-foreground">уже привязан</span>
                              ) : selected ? (
                                <Badge variant="secondary" size="xs">Выбран</Badge>
                              ) : null}
                            </ItemActions>
                          </Item>
                        )
                      })}
                    </div>
                  </FramePanel>
                </Frame>
                <Input
                  className="h-8 text-xs"
                  placeholder="Комментарий (необязательно)"
                  value={newComment}
                  onChange={(e) => setNewComment(e.target.value)}
                />
                <Button size="sm" disabled={selectedPicks.length === 0} onClick={addSelectedBindings}>
                  <PlusIcon className="size-3.5" />Привязать
                </Button>
              </div>

              <div className="flex flex-col gap-1.5 py-3">
                {form.bindings.length === 0 && (
                  <p className="text-xs text-muted-foreground">Нет привязанных интерфейсов</p>
                )}
                {form.bindings.map((b) => (
                  <div key={b.id} className="flex items-center gap-2 py-1">
                    <Flag code={b.serverCountry} size={12} />
                    <span className="font-mono text-xs truncate">{bindingTitle(b)}</span>
                    <Badge variant={TYPE_VARIANT[b.interfaceType]} size="sm">{IFACE_TYPE_LABEL[b.interfaceType]}</Badge>
                    {b.interfaceType === "wg" && !(b.peerPublicKey ?? "") ? (
                      <Badge variant="warning-light" size="sm">весь интерфейс</Badge>
                    ) : null}
                    <span className="text-[10px] text-muted-foreground truncate">{b.serverName}</span>
                    <Button
                      size="sm"
                      variant="ghost"
                      className="size-7 p-0 ml-auto text-muted-foreground hover:text-destructive"
                      onClick={() => removeBinding(b.id)}
                    >
                      <TrashIcon className="size-3.5" />
                    </Button>
                  </div>
                ))}
              </div>
            </StepperContent>
          </StepperPanel>
        </Stepper>

        <SheetFooter className="px-6 py-4 border-t shrink-0 flex-row gap-2">
          <SheetClose render={<Button variant="outline" />}>Отмена</SheetClose>
          {sheetStep > 1 && (
            <Button variant="outline" onClick={() => setSheetStep((s) => s - 1)}>Назад</Button>
          )}
          {sheetStep < 4 ? (
            <Button className="ml-auto" onClick={() => setSheetStep((s) => s + 1)}>Далее</Button>
          ) : (
            <Button className="ml-auto" disabled={saving} onClick={submit}>
              {isCreate ? "Создать" : "Сохранить"}
            </Button>
          )}
        </SheetFooter>
      </SheetContent>
    </Sheet>
  )
}

export { UserSheet, type UserSheetProps }
