import {
  CheckCircleOutlined,
  ClockCircleOutlined,
  DeleteOutlined,
  EditOutlined,
  EyeOutlined,
  LinkOutlined,
  ThunderboltOutlined,
  FileSearchOutlined,
  InfoCircleOutlined,
  CameraOutlined,
  ReloadOutlined,
} from '@ant-design/icons'
import {
  Badge,
  Breadcrumb,
  Button,
  Card,
  Col,
  Descriptions,
  Input,
  Modal,
  Popconfirm,
  Progress,
  Result,
  Row,
  Select,
  Space,
  Spin,
  Table,
  Tag,
  Tooltip,
  Typography,
  message,
} from 'antd'
import { useQueryClient } from '@tanstack/react-query'
import dayjs from 'dayjs'
import { useState } from 'react'
import { useNavigate, useParams } from 'react-router-dom'
import { useAlerts, useAcknowledgeAlert, useResolveAlert, type AlertItem } from '../api/alerts'
import { useDevice, useDeleteDevice, useObject, useDeviceCredentials, type DeviceItem, type ObjectItem, type DeviceCredentials } from '../api/objects'
import { getDeviceWebUrl } from '../utils/deviceUrl'
import { elapsedAgo } from '../utils/time'
import { useSnapshots, useSnapshotDiff } from '../api/snapshots'
import { useDeviceTasks, useTask, useCreateTask, type Task } from '../api/tasks'
import { DeviceEditModal } from '../components/DeviceEditModal'
import { CategoryTag, DeviceStatusBadge, TaskStatusBadge } from '../components/StatusBadge'
import { useMonitorSSE } from '../hooks/useMonitorSSE'

// ─── Constants ────────────────────────────────────────────────────────────────

const ALERT_STATUS_COLOR: Record<string, string> = {
  open: 'error',
  acknowledged: 'warning',
  resolved: 'success',
}
const ALERT_STATUS_LABEL: Record<string, string> = {
  open: 'Открыт',
  acknowledged: 'Подтверждён',
  resolved: 'Закрыт',
}
const LOCATION_LABEL: Record<string, string> = {
  server_room: 'Серверная',
  rack: 'Стойка',
  street: 'Улица',
}
const SOURCE_COLOR: Record<string, string> = {
  manual: 'blue',
  db_sync: 'purple',
  auto_ssh: 'green',
  csv: 'orange',
  sheets: 'cyan',
}
const SOURCE_LABEL: Record<string, string> = {
  manual: 'Вручную',
  db_sync: 'Синхронизация БД',
  auto_ssh: 'SSH Discovery',
  csv: 'CSV импорт',
  sheets: 'Google Sheets',
}

// Known snapshot action per device category.
// Mikrotik is detected separately via vendor string.
const CATEGORY_SNAPSHOT: Record<string, { type: string; needPath: boolean; defaultPath: string }> = {
  main_server: { type: 'get_file', needPath: true, defaultPath: '/etc/caps/config.ini' },
  vm:          { type: 'get_file', needPath: true, defaultPath: '/etc/caps/config.ini' },
  embedded:    { type: 'get_file', needPath: true, defaultPath: '/etc/caps/config.ini' },
  io_board:    { type: 'get_file', needPath: true, defaultPath: '/etc/caps/config.ini' },
  other:       { type: 'get_file', needPath: true, defaultPath: '/etc/caps/config.ini' },
}

function getSnapshotConfig(device: DeviceItem) {
  if (
    device.category === 'router' ||
    device.vendor?.toLowerCase().includes('mikrotik')
  ) {
    return { type: 'mikrotik_get_config', needPath: false, defaultPath: '' }
  }
  return CATEGORY_SNAPSHOT[device.category] ?? null
}

// ─── SSH / Credentials block ──────────────────────────────────────────────────

function SshBlock({
  device,
  obj,
  creds,
  credsLoading,
}: {
  device: DeviceItem
  obj: ObjectItem | undefined
  creds: DeviceCredentials | undefined
  credsLoading: boolean
}) {
  const lastAuth = device.ssh_last_auth

  const effectiveUser =
    lastAuth?.username
      ? String(lastAuth.username)
      : device.ssh_user_override ?? obj?.ssh_user ?? null

  const effectivePort = device.ssh_port_override ?? 22

  const usesKey = String(lastAuth?.type) === 'key' || device.ssh_key_id_override != null

  // Effective SSH password: device override first, then object level
  const effectiveSshPassword = creds?.ssh_password_device ?? creds?.ssh_password_object ?? null
  const sshPasswordSource = creds?.ssh_password_device
    ? 'device'
    : creds?.ssh_password_object
    ? 'объект'
    : null

  return (
    <Descriptions
      bordered
      size="small"
      column={1}
      labelStyle={{ width: 160 }}
      style={{ marginTop: 16 }}
      title={<Typography.Text strong style={{ fontSize: 13 }}>SSH / Авторизация</Typography.Text>}
    >
      <Descriptions.Item label="Логин">
        <Space size={6}>
          {effectiveUser
            ? <Typography.Text code copyable>{effectiveUser}</Typography.Text>
            : <Typography.Text type="secondary">Не задан</Typography.Text>}
          {device.ssh_user_override
            ? <Tag color="blue" style={{ fontSize: 10 }}>device</Tag>
            : obj?.ssh_user
            ? <Tag style={{ fontSize: 10 }}>объект</Tag>
            : null}
        </Space>
      </Descriptions.Item>

      <Descriptions.Item label="Пароль">
        {usesKey ? (
          <Space size={6}>
            <Tag color="purple">SSH ключ</Tag>
            {(lastAuth?.key_id != null || device.ssh_key_id_override != null) && (
              <Typography.Text type="secondary" style={{ fontSize: 12 }}>
                key_id={String(lastAuth?.key_id ?? device.ssh_key_id_override)}
              </Typography.Text>
            )}
          </Space>
        ) : credsLoading ? (
          <Spin size="small" />
        ) : effectiveSshPassword ? (
          <Space size={6}>
            <Typography.Text code copyable>{effectiveSshPassword}</Typography.Text>
            {sshPasswordSource && <Tag style={{ fontSize: 10 }}>{sshPasswordSource}</Tag>}
          </Space>
        ) : (
          <Typography.Text type="secondary">Не задан</Typography.Text>
        )}
      </Descriptions.Item>

      <Descriptions.Item label="Порт">
        <Space size={6}>
          <Typography.Text code>{effectivePort}</Typography.Text>
          {device.ssh_port_override && <Tag color="blue" style={{ fontSize: 10 }}>device</Tag>}
        </Space>
      </Descriptions.Item>

      {lastAuth && (
        <Descriptions.Item label="Последнее подкл.">
          <Space size={4} wrap>
            <Tag color="green">успешно</Tag>
            <Tag>{String(lastAuth.type) === 'key' ? 'ключ' : 'пароль'}</Tag>
            {lastAuth.username && (
              <Typography.Text type="secondary" style={{ fontSize: 12 }}>
                {String(lastAuth.username)}
              </Typography.Text>
            )}
          </Space>
        </Descriptions.Item>
      )}
    </Descriptions>
  )
}

// ─── Device meta smart render ─────────────────────────────────────────────────

function DeviceMetaBlock({ device }: { device: DeviceItem }) {
  const meta = device.device_meta
  if (!meta || Object.keys(meta).length === 0) return null

  // Keys already shown in SystemInfoBlock — skip them here
  const systemInfoKeys = new Set([
    'os', 'uptime', 'load_1m', 'load_5m', 'load_15m', 'cpu_cores',
    'mem_total_mb', 'mem_used_mb', 'mem_free_mb', 'mem_percent',
    'disks', 'top_processes', 'temps',
  ])

  const category = device.category

  // Structured fields per category
  const knownKeys: Record<string, string> = {}
  const remaining: Record<string, unknown> = {}

  if (category === 'camera') {
    const cameraKeys = ['plugin', 'cls', 'stream_url', 'rtsp_url', 'channel', 'brand']
    for (const [k, v] of Object.entries(meta)) {
      if (cameraKeys.includes(k)) knownKeys[k] = String(v)
      else if (!systemInfoKeys.has(k)) remaining[k] = v
    }
  } else if (category === 'router' || device.vendor?.toLowerCase().includes('mikrotik')) {
    const routerKeys = ['identity', 'board_name', 'ros_version', 'architecture', 'platform']
    for (const [k, v] of Object.entries(meta)) {
      if (routerKeys.includes(k)) knownKeys[k] = String(v)
      else if (!systemInfoKeys.has(k)) remaining[k] = v
    }
  } else {
    for (const [k, v] of Object.entries(meta)) {
      if (!systemInfoKeys.has(k)) remaining[k] = v
    }
  }

  const LABEL_MAP: Record<string, string> = {
    plugin: 'Plugin',
    cls: 'Тип',
    stream_url: 'Stream URL',
    rtsp_url: 'RTSP URL',
    channel: 'Канал',
    brand: 'Бренд',
    identity: 'Identity',
    board_name: 'Board',
    ros_version: 'RouterOS',
    architecture: 'Архитектура',
    platform: 'Платформа',
  }

  const hasKnown = Object.keys(knownKeys).length > 0
  const hasRemaining = Object.keys(remaining).length > 0

  return (
    <Card size="small" title="Метаданные устройства" style={{ marginBottom: 16 }}>
      {hasKnown && (
        <Descriptions size="small" column={1} style={{ marginBottom: hasRemaining ? 8 : 0 }}>
          {Object.entries(knownKeys).map(([k, v]) => (
            <Descriptions.Item key={k} label={LABEL_MAP[k] ?? k}>
              {k.includes('url') || k.includes('rtsp')
                ? <Typography.Text code copyable style={{ fontSize: 11 }}>{v}</Typography.Text>
                : <Typography.Text>{v}</Typography.Text>}
            </Descriptions.Item>
          ))}
        </Descriptions>
      )}
      {hasRemaining && (
        <pre style={{ fontSize: 11, margin: 0, maxHeight: 200, overflow: 'auto', background: '#fafafa', padding: 8, borderRadius: 4, border: '1px solid #f0f0f0' }}>
          {JSON.stringify(remaining, null, 2)}
        </pre>
      )}
    </Card>
  )
}

// ─── Connection params smart render ──────────────────────────────────────────

function ConnectionParamsBlock({
  device,
  creds,
  credsLoading,
}: {
  device: DeviceItem
  creds: DeviceCredentials | undefined
  credsLoading: boolean
}) {
  const params = device.connection_params
  if (!params || Object.keys(params).length === 0) return null

  const knownKeys = ['port', 'protocol', 'auth_type', 'username', 'url', 'api_port', 'web_port']
  const displayed: Record<string, unknown> = {}
  const remaining: Record<string, unknown> = {}

  for (const [k, v] of Object.entries(params)) {
    if (k === 'password') continue  // shown separately, decrypted
    if (knownKeys.includes(k)) displayed[k] = v
    else remaining[k] = v
  }

  const LABEL_MAP: Record<string, string> = {
    port: 'Порт',
    protocol: 'Протокол',
    auth_type: 'Тип авторизации',
    username: 'Логин',
    url: 'URL',
    api_port: 'API порт',
    web_port: 'Web порт',
  }
  const AUTH_COLOR: Record<string, string> = {
    basic: 'blue',
    digest: 'orange',
    bearer: 'green',
    none: 'default',
  }

  const hasDisplayed = Object.keys(displayed).length > 0
  const hasRemaining = Object.keys(remaining).length > 0
  const hasPassword = 'password' in params

  return (
    <Card size="small" title="Параметры подключения">
      <Descriptions size="small" column={1} style={{ marginBottom: hasRemaining ? 8 : 0 }}>
        {hasDisplayed && Object.entries(displayed).map(([k, v]) => (
          <Descriptions.Item key={k} label={LABEL_MAP[k] ?? k}>
            {k === 'auth_type'
              ? <Tag color={AUTH_COLOR[String(v)] ?? 'default'}>{String(v)}</Tag>
              : k === 'protocol'
              ? <Tag color={String(v) === 'https' ? 'green' : 'blue'}>{String(v).toUpperCase()}</Tag>
              : k === 'url'
              ? <Typography.Text code copyable style={{ fontSize: 11 }}>{String(v)}</Typography.Text>
              : <Typography.Text code>{String(v)}</Typography.Text>}
          </Descriptions.Item>
        ))}
        {hasPassword && (
          <Descriptions.Item label="Пароль">
            {credsLoading
              ? <Spin size="small" />
              : creds?.connection_password
              ? <Typography.Text code copyable>{creds.connection_password}</Typography.Text>
              : <Typography.Text type="secondary">Не задан</Typography.Text>}
          </Descriptions.Item>
        )}
      </Descriptions>
      {hasRemaining && (
        <pre style={{ fontSize: 11, margin: 0, maxHeight: 200, overflow: 'auto', background: '#fafafa', padding: 8, borderRadius: 4, border: '1px solid #f0f0f0' }}>
          {JSON.stringify(remaining, null, 2)}
        </pre>
      )}
    </Card>
  )
}

// ─── System Info block (from device_meta or latest debian_system_info task) ──

function SystemInfoFromTask({ taskId, deviceId }: { taskId: string; deviceId: number }) {
  const { data: detail, isLoading } = useTask(taskId)
  const dr = detail?.device_results.find((r) => r.device_id === deviceId)
  const data = dr?.data as Record<string, unknown> | null | undefined

  if (isLoading) return <Spin size="small" />
  if (!data || Object.keys(data).length === 0) return <Typography.Text type="secondary">Нет данных</Typography.Text>

  return <SystemInfoRender data={data} />
}

function SystemInfoRender({ data }: { data: Record<string, unknown> }) {
  const memTotal = data.mem_total_mb as number | undefined
  const memUsed = data.mem_used_mb as number | undefined
  const memPct = data.mem_percent as number | undefined
  const disks = data.disks as { mount: string; size: string; used: string; avail: string; pct: string }[] | undefined
  const temps = data.temps as string[] | undefined

  return (
    <Space direction="vertical" style={{ width: '100%' }} size={8}>
      {data.os && (
        <Descriptions size="small" column={1}>
          <Descriptions.Item label="ОС">{String(data.os)}</Descriptions.Item>
          {data.uptime && <Descriptions.Item label="Uptime">{String(data.uptime)}</Descriptions.Item>}
          {(data.load_1m || data.cpu_cores) && (
            <Descriptions.Item label="CPU">
              <Space size={4}>
                {data.cpu_cores && <span>Ядра: <b>{String(data.cpu_cores)}</b></span>}
                {data.load_1m && <span>Load: <b>{String(data.load_1m)}</b> / {String(data.load_5m ?? '?')} / {String(data.load_15m ?? '?')}</span>}
              </Space>
            </Descriptions.Item>
          )}
        </Descriptions>
      )}

      {memTotal !== undefined && memUsed !== undefined && (
        <div>
          <Typography.Text type="secondary" style={{ fontSize: 12 }}>
            RAM: {memUsed} MB / {memTotal} MB
          </Typography.Text>
          <Progress
            percent={memPct ?? Math.round((memUsed / memTotal) * 100)}
            size="small"
            status={((memPct ?? 0) > 90) ? 'exception' : 'normal'}
            style={{ marginTop: 2 }}
          />
        </div>
      )}

      {disks && disks.length > 0 && (
        <div>
          <Typography.Text type="secondary" style={{ fontSize: 12, display: 'block', marginBottom: 4 }}>Диски:</Typography.Text>
          {disks.filter((d) => !isNaN(parseInt(d.pct))).map((d) => {
            const pctNum = parseInt(d.pct)
            return (
              <div key={d.mount} style={{ marginBottom: 6 }}>
                <Space style={{ width: '100%', justifyContent: 'space-between' }}>
                  <Typography.Text code style={{ fontSize: 11 }}>{d.mount}</Typography.Text>
                  <Typography.Text type="secondary" style={{ fontSize: 11 }}>{d.used} / {d.size} ({d.pct})</Typography.Text>
                </Space>
                <Progress
                  percent={isNaN(pctNum) ? 0 : pctNum}
                  size="small"
                  status={pctNum > 90 ? 'exception' : pctNum > 75 ? 'active' : 'normal'}
                  showInfo={false}
                  style={{ marginTop: 2 }}
                />
              </div>
            )
          })}
        </div>
      )}

      {temps && temps.length > 0 && (
        <div>
          <Typography.Text type="secondary" style={{ fontSize: 12 }}>Температуры: </Typography.Text>
          {temps.map((t, i) => <Tag key={i} color="orange" style={{ fontSize: 11 }}>{t}</Tag>)}
        </div>
      )}
    </Space>
  )
}

function SystemInfoBlock({ device, tasks }: { device: DeviceItem; tasks: Task[] | undefined }) {
  // Check device_meta first (manually stored)
  const metaHasSystemInfo =
    device.device_meta &&
    ('os' in device.device_meta || 'mem_total_mb' in device.device_meta || 'disks' in device.device_meta)

  if (metaHasSystemInfo) {
    return (
      <Card size="small" title="Системная информация" style={{ marginBottom: 16 }}>
        <SystemInfoRender data={device.device_meta as Record<string, unknown>} />
      </Card>
    )
  }

  // Fallback: find most recent successful debian_system_info task
  const latestTask = tasks
    ?.filter((t) => t.type === 'debian_system_info' && t.status === 'success')
    .sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime())[0]

  if (!latestTask) return null

  return (
    <Card
      size="small"
      title={
        <Space>
          Системная информация
          <Typography.Text type="secondary" style={{ fontSize: 11, fontWeight: 'normal' }}>
            (из задачи {dayjs(latestTask.created_at).format('DD.MM.YY HH:mm')})
          </Typography.Text>
        </Space>
      }
      style={{ marginBottom: 16 }}
    >
      <SystemInfoFromTask taskId={latestTask.id} deviceId={device.id} />
    </Card>
  )
}

// ─── Alerts tab ───────────────────────────────────────────────────────────────

function AlertsTab({ deviceId }: { deviceId: number }) {
  const [statusFilter, setStatusFilter] = useState<string | undefined>(undefined)
  const { data: alerts, isLoading } = useAlerts({ device_id: deviceId, status: statusFilter })
  const acknowledge = useAcknowledgeAlert()
  const resolve = useResolveAlert()

  const columns = [
    { title: 'Сообщение', dataIndex: 'message', key: 'message' },
    {
      title: 'Статус',
      dataIndex: 'status',
      key: 'status',
      width: 140,
      render: (s: string) => (
        <Badge status={ALERT_STATUS_COLOR[s] as any} text={ALERT_STATUS_LABEL[s] ?? s} />
      ),
    },
    {
      title: 'Создан',
      dataIndex: 'created_at',
      key: 'created_at',
      width: 160,
      render: (v: string) => dayjs(v).format('DD.MM.YY HH:mm'),
    },
    {
      title: 'Подтверждён',
      dataIndex: 'acknowledged_by_username',
      key: 'ack',
      width: 140,
      render: (v: string | null, row: AlertItem) =>
        v ? (
          <Tooltip title={row.acknowledged_at ? dayjs(row.acknowledged_at).format('DD.MM.YY HH:mm') : ''}>
            <Typography.Text type="secondary">{v}</Typography.Text>
          </Tooltip>
        ) : '—',
    },
    {
      title: '',
      key: 'actions',
      width: 120,
      render: (_: unknown, row: AlertItem) => (
        <Space size={4}>
          {row.status === 'open' && (
            <Tooltip title="Подтвердить">
              <Button
                size="small"
                icon={<CheckCircleOutlined />}
                loading={acknowledge.isPending}
                onClick={() => acknowledge.mutateAsync(row.id).catch(() => message.error('Ошибка'))}
              />
            </Tooltip>
          )}
          {row.status !== 'resolved' && (
            <Tooltip title="Закрыть">
              <Button
                size="small"
                danger
                icon={<DeleteOutlined />}
                loading={resolve.isPending}
                onClick={() => resolve.mutateAsync(row.id).catch(() => message.error('Ошибка'))}
              />
            </Tooltip>
          )}
        </Space>
      ),
    },
  ]

  return (
    <>
      <div style={{ marginBottom: 12 }}>
        <Select
          placeholder="Все статусы"
          allowClear
          style={{ width: 180 }}
          value={statusFilter}
          onChange={setStatusFilter}
          options={[
            { value: 'open', label: 'Открытые' },
            { value: 'acknowledged', label: 'Подтверждённые' },
            { value: 'resolved', label: 'Закрытые' },
          ]}
        />
      </div>
      <Table
        dataSource={alerts ?? []}
        columns={columns}
        rowKey="id"
        loading={isLoading}
        size="small"
        pagination={{ pageSize: 20 }}
        locale={{ emptyText: 'Нет алертов' }}
      />
    </>
  )
}

// ─── Camera tab ───────────────────────────────────────────────────────────────

function CameraStatusInfo({ deviceId, tasks }: { deviceId: number; tasks: Task[] | undefined }) {
  const latestTask = tasks
    ?.filter((t) => t.type === 'camera_get_status' && t.status === 'success')
    .sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime())[0]

  if (!latestTask) return null

  return <CameraStatusFromTask taskId={latestTask.id} deviceId={deviceId} taskDate={latestTask.created_at} />
}

function CameraStatusFromTask({ taskId, deviceId, taskDate }: { taskId: string; deviceId: number; taskDate: string }) {
  const { data: detail, isLoading } = useTask(taskId)
  const dr = detail?.device_results.find((r) => r.device_id === deviceId)
  const data = dr?.data as { device_info?: Record<string, unknown>; system_time?: Record<string, unknown> } | undefined

  if (isLoading) return <Spin size="small" />
  if (!data?.device_info) return null

  const di = data.device_info
  const st = data.system_time ?? {}

  return (
    <Card
      size="small"
      title={
        <Space>
          Последний статус
          <Typography.Text type="secondary" style={{ fontSize: 11, fontWeight: 'normal' }}>
            ({dayjs(taskDate).format('DD.MM.YY HH:mm')})
          </Typography.Text>
        </Space>
      }
      style={{ marginBottom: 16 }}
    >
      <Descriptions size="small" column={2}>
        {di.model && <Descriptions.Item label="Модель">{String(di.model)}</Descriptions.Item>}
        {di.firmwareVersion && <Descriptions.Item label="Прошивка">{String(di.firmwareVersion)}</Descriptions.Item>}
        {di.serialNumber && <Descriptions.Item label="Серийный №">{String(di.serialNumber)}</Descriptions.Item>}
        {di.macAddress && <Descriptions.Item label="MAC">{String(di.macAddress)}</Descriptions.Item>}
        {st.localTime && <Descriptions.Item label="Время камеры">{String(st.localTime)}</Descriptions.Item>}
        {st.timeZone && <Descriptions.Item label="Часовой пояс">{String(st.timeZone)}</Descriptions.Item>}
      </Descriptions>
    </Card>
  )
}

function CameraTab({
  device,
  objId,
  tasks,
  creds,
}: {
  device: DeviceItem
  objId: number
  tasks: Task[] | undefined
  creds: DeviceCredentials | undefined
}) {
  const [snapshotKey, setSnapshotKey] = useState(0)
  const [snapshotError, setSnapshotError] = useState<string | null>(null)
  const [channel, setChannel] = useState(1)
  const createTask = useCreateTask()

  const params = device.connection_params ?? {}
  const meta = device.device_meta ?? {}
  const httpPort = meta.http_port ?? 80
  const streamUrl: string | null = (params.stream_url as string) ?? null
  const authType: string | null = (params.auth_type as string) ?? null
  const webUser: string | null = (params.username as string) ?? device.ssh_user_override ?? null

  // Build default RTSP URL if not in connection_params
  const rtspUrl = streamUrl ?? `rtsp://${device.ip}:554/Streaming/Channels/${channel}01`

  const snapshotSrc = `/api/v1/objects/${objId}/devices/${device.id}/camera/snapshot?channel=${channel}&_k=${snapshotKey}`

  const handleGetStatus = async () => {
    try {
      const task = await createTask.mutateAsync({
        type: 'camera_get_status',
        target_scope: { type: 'device', id: device.id },
        params: {},
      })
      message.success(
        <span>Задача запущена. <a href={`/tasks/${task.id}`} target="_blank" rel="noopener noreferrer">Открыть</a></span>,
        5,
      )
    } catch {
      message.error('Не удалось запустить задачу')
    }
  }

  return (
    <Row gutter={24}>
      <Col xs={24} lg={14}>
        {/* Connection parameters */}
        <Card size="small" title="Параметры подключения" style={{ marginBottom: 16 }}>
          <Descriptions size="small" column={1}>
            <Descriptions.Item label="HTTP порт">
              <Typography.Text code>{String(httpPort)}</Typography.Text>
            </Descriptions.Item>
            {authType && (
              <Descriptions.Item label="Авторизация">
                <Tag color={authType === 'digest' ? 'orange' : 'blue'}>{authType}</Tag>
              </Descriptions.Item>
            )}
            {webUser && (
              <Descriptions.Item label="Логин (веб)">
                <Typography.Text code copyable>{webUser}</Typography.Text>
              </Descriptions.Item>
            )}
            {creds?.connection_password && (
              <Descriptions.Item label="Пароль (веб)">
                <Typography.Text code copyable>{creds.connection_password}</Typography.Text>
              </Descriptions.Item>
            )}
            <Descriptions.Item label="RTSP поток">
              <Space>
                <Typography.Text code copyable style={{ fontSize: 11 }}>{rtspUrl}</Typography.Text>
                <Tooltip title="Открыть в VLC (если установлен)">
                  <Button
                    size="small"
                    type="link"
                    onClick={() => { window.open(`vlc://${rtspUrl}`) }}
                  >
                    VLC
                  </Button>
                </Tooltip>
              </Space>
            </Descriptions.Item>
            {params.frame_url && (
              <Descriptions.Item label="Frame URL">
                <Typography.Text code copyable style={{ fontSize: 11 }}>{String(params.frame_url)}</Typography.Text>
              </Descriptions.Item>
            )}
          </Descriptions>
        </Card>

        {/* Last camera status */}
        <CameraStatusInfo deviceId={device.id} tasks={tasks} />

        <Button
          icon={<InfoCircleOutlined />}
          loading={createTask.isPending}
          onClick={handleGetStatus}
          style={{ marginBottom: 16 }}
        >
          Получить статус камеры
        </Button>
      </Col>

      <Col xs={24} lg={10}>
        {/* Live snapshot */}
        <Card
          size="small"
          title="Снимок с камеры"
          extra={
            <Space size={8}>
              <Select
                size="small"
                value={channel}
                onChange={setChannel}
                options={[
                  { value: 1, label: 'Канал 1' },
                  { value: 2, label: 'Канал 2' },
                  { value: 3, label: 'Канал 3' },
                ]}
                style={{ width: 90 }}
              />
              <Button
                size="small"
                icon={<ReloadOutlined />}
                onClick={() => { setSnapshotError(null); setSnapshotKey((k) => k + 1) }}
              >
                Обновить
              </Button>
            </Space>
          }
        >
          {snapshotError ? (
            <div style={{ padding: '16px 0', textAlign: 'center' }}>
              <Typography.Text type="danger">{snapshotError}</Typography.Text>
              <br />
              <Button
                size="small"
                style={{ marginTop: 8 }}
                onClick={() => { setSnapshotError(null); setSnapshotKey((k) => k + 1) }}
              >
                Повторить
              </Button>
            </div>
          ) : (
            <img
              key={snapshotKey}
              src={snapshotSrc}
              alt="Camera snapshot"
              style={{ width: '100%', borderRadius: 4, display: 'block' }}
              onError={() => setSnapshotError('Не удалось загрузить снимок. Проверьте подключение и кредиалы камеры.')}
              onLoad={() => setSnapshotError(null)}
            />
          )}
          <Typography.Text type="secondary" style={{ fontSize: 11, display: 'block', marginTop: 8 }}>
            Снимок загружается через сервер — не требует прямого доступа к камере из браузера
          </Typography.Text>
        </Card>
      </Col>
    </Row>
  )
}

// ─── Snapshots tab ────────────────────────────────────────────────────────────

function SnapshotsTab({ objId, deviceId, device }: { objId: number; deviceId: number; device: DeviceItem }) {
  const { data: snapshots, isLoading, refetch } = useSnapshots(objId, { device_id: deviceId })
  const [selectedA, setSelectedA] = useState<number | null>(null)
  const [selectedB, setSelectedB] = useState<number | null>(null)
  const { data: diffData, isFetching: diffLoading } = useSnapshotDiff(objId, selectedA, selectedB)
  const createTask = useCreateTask()
  const [snapshotModalOpen, setSnapshotModalOpen] = useState(false)
  const [snapshotPath, setSnapshotPath] = useState('')

  const snapshotConfig = getSnapshotConfig(device)

  const handleOpenSnapshotModal = () => {
    if (!snapshotConfig) return
    if (!snapshotConfig.needPath) {
      // Mikrotik — run directly
      handleTakeSnapshot('')
      return
    }
    setSnapshotPath(snapshotConfig.defaultPath)
    setSnapshotModalOpen(true)
  }

  const handleTakeSnapshot = async (path: string) => {
    if (!snapshotConfig) return
    try {
      const params = snapshotConfig.needPath ? { path } : {}
      const task = await createTask.mutateAsync({
        type: snapshotConfig.type,
        target_scope: { type: 'device', id: deviceId },
        params,
      })
      setSnapshotModalOpen(false)
      message.success(
        <span>
          Задача запущена.{' '}
          <a href={`/tasks/${task.id}`} target="_blank" rel="noopener noreferrer">
            Открыть задачу
          </a>
        </span>,
        6,
      )
      // Refresh snapshots after a short delay
      setTimeout(() => refetch(), 5000)
    } catch {
      message.error('Не удалось запустить задачу')
    }
  }

  const snapshotOptions = (snapshots ?? []).map((s) => ({
    value: s.id,
    label: `${dayjs(s.created_at).format('DD.MM.YY HH:mm')} — ${s.sha256.slice(0, 8)}`,
  }))

  const columns = [
    {
      title: 'Дата',
      dataIndex: 'created_at',
      key: 'created_at',
      width: 160,
      render: (v: string) => dayjs(v).format('DD.MM.YY HH:mm:ss'),
    },
    {
      title: 'SHA-256',
      dataIndex: 'sha256',
      key: 'sha256',
      render: (v: string) => (
        <Tooltip title={v}>
          <code>{v.slice(0, 12)}…</code>
        </Tooltip>
      ),
    },
    {
      title: 'Размер',
      dataIndex: 'size',
      key: 'size',
      width: 100,
      render: (v: number) => `${v} Б`,
    },
    {
      title: 'Метка',
      dataIndex: 'label',
      key: 'label',
      render: (v: string | null) => v ?? '—',
    },
  ]

  const renderDiff = (diff: string) => {
    if (!diff) return <Typography.Text type="secondary">Нет изменений</Typography.Text>
    return (
      <pre style={{ fontSize: 12, maxHeight: 500, overflow: 'auto', background: '#fafafa', padding: 12, border: '1px solid #e8e8e8', borderRadius: 6 }}>
        {diff.split('\n').map((line, i) => {
          let color = 'inherit'
          if (line.startsWith('+') && !line.startsWith('+++')) color = '#237804'
          else if (line.startsWith('-') && !line.startsWith('---')) color = '#a8071a'
          else if (line.startsWith('@@')) color = '#096dd9'
          return <span key={i} style={{ color, display: 'block' }}>{line}</span>
        })}
      </pre>
    )
  }

  return (
    <>
      {/* Take snapshot button */}
      <div style={{ marginBottom: 16 }}>
        {snapshotConfig ? (
          <Tooltip
            title={
              snapshotConfig.needPath
                ? `Снять файл: ${snapshotConfig.defaultPath}`
                : 'Экспортировать конфигурацию RouterOS'
            }
          >
            <Button
              type="primary"
              icon={<CameraOutlined />}
              loading={createTask.isPending}
              onClick={handleOpenSnapshotModal}
            >
              Снять снапшот
            </Button>
          </Tooltip>
        ) : (
          <Tooltip title="Для данной категории устройств снапшоты не поддерживаются">
            <Button icon={<CameraOutlined />} disabled>
              Снять снапшот
            </Button>
          </Tooltip>
        )}
      </div>

      <Table
        dataSource={snapshots ?? []}
        columns={columns}
        rowKey="id"
        loading={isLoading}
        size="small"
        pagination={{ pageSize: 20 }}
        locale={{ emptyText: 'Снапшоты не найдены' }}
        style={{ marginBottom: 24 }}
      />

      <Typography.Title level={5} style={{ marginBottom: 12 }}>Сравнить снапшоты</Typography.Title>
      <Space style={{ marginBottom: 16 }} wrap>
        <Select
          placeholder="Снапшот A (старый)"
          style={{ width: 280 }}
          options={snapshotOptions}
          value={selectedA}
          onChange={setSelectedA}
          allowClear
        />
        <Select
          placeholder="Снапшот B (новый)"
          style={{ width: 280 }}
          options={snapshotOptions}
          value={selectedB}
          onChange={setSelectedB}
          allowClear
        />
      </Space>
      {diffLoading && <Spin />}
      {diffData && !diffLoading && (
        diffData.is_identical
          ? <Typography.Text type="secondary">Снапшоты идентичны</Typography.Text>
          : renderDiff(diffData.diff)
      )}

      {/* Snapshot path modal */}
      <Modal
        open={snapshotModalOpen}
        title="Снять снапшот файла"
        okText="Запустить"
        cancelText="Отмена"
        onCancel={() => setSnapshotModalOpen(false)}
        onOk={() => handleTakeSnapshot(snapshotPath)}
        confirmLoading={createTask.isPending}
      >
        <Space direction="vertical" style={{ width: '100%' }}>
          <Typography.Text type="secondary">
            Укажите путь к файлу на устройстве <code>{device.ip}</code>
          </Typography.Text>
          <Input
            value={snapshotPath}
            onChange={(e) => setSnapshotPath(e.target.value)}
            placeholder="/etc/caps/config.ini"
            addonBefore={<FileSearchOutlined />}
          />
        </Space>
      </Modal>
    </>
  )
}

// ─── Tasks tab ────────────────────────────────────────────────────────────────

function TaskResultRow({ taskId, deviceId }: { taskId: string; deviceId: number }) {
  const { data: detail, isLoading } = useTask(taskId)
  const deviceResult = detail?.device_results.find((r) => r.device_id === deviceId)

  if (isLoading) return <Spin size="small" />
  if (!deviceResult) return <Typography.Text type="secondary">Нет данных</Typography.Text>

  return (
    <div style={{ padding: '8px 16px', background: '#fafafa', borderRadius: 4 }}>
      <Space size={16} style={{ marginBottom: 8 }}>
        <span><b>Статус:</b> {deviceResult.status}</span>
        {deviceResult.exit_code !== null && <span><b>Код:</b> {deviceResult.exit_code}</span>}
        {deviceResult.duration_ms !== null && <span><b>Время:</b> {deviceResult.duration_ms}мс</span>}
        {deviceResult.executed_at && (
          <span><b>Выполнено:</b> {dayjs(deviceResult.executed_at).format('DD.MM.YY HH:mm:ss')}</span>
        )}
      </Space>
      {deviceResult.stdout && (
        <pre style={{ fontSize: 11, maxHeight: 200, overflow: 'auto', background: '#fff', padding: 8, border: '1px solid #e8e8e8', borderRadius: 4, marginBottom: 4 }}>
          {deviceResult.stdout}
        </pre>
      )}
      {deviceResult.stderr && (
        <pre style={{ fontSize: 11, maxHeight: 100, overflow: 'auto', background: '#fff4f4', padding: 8, border: '1px solid #ffa39e', borderRadius: 4, color: '#a8071a' }}>
          {deviceResult.stderr}
        </pre>
      )}
      {deviceResult.data && Object.keys(deviceResult.data).length > 0 && (
        <pre style={{ fontSize: 11, maxHeight: 200, overflow: 'auto', background: '#f6ffed', padding: 8, border: '1px solid #b7eb8f', borderRadius: 4 }}>
          {JSON.stringify(deviceResult.data, null, 2)}
        </pre>
      )}
    </div>
  )
}

function TasksTab({ deviceId }: { deviceId: number }) {
  const navigate = useNavigate()
  const { data: tasks, isLoading } = useDeviceTasks(deviceId)

  const columns = [
    {
      title: 'Тип',
      dataIndex: 'type',
      key: 'type',
      render: (v: string) => <code style={{ fontSize: 12 }}>{v}</code>,
    },
    {
      title: 'Статус',
      dataIndex: 'status',
      key: 'status',
      width: 140,
      render: (v: string) => <TaskStatusBadge status={v} />,
    },
    {
      title: 'Цель',
      dataIndex: 'target_label',
      key: 'target_label',
      render: (v: string | null) => v ?? '—',
    },
    {
      title: 'Создана',
      dataIndex: 'created_at',
      key: 'created_at',
      width: 160,
      render: (v: string) => dayjs(v).format('DD.MM.YY HH:mm'),
    },
    {
      title: 'Завершена',
      dataIndex: 'finished_at',
      key: 'finished_at',
      width: 160,
      render: (v: string | null) => v ? dayjs(v).format('DD.MM.YY HH:mm') : '—',
    },
    {
      title: '',
      key: 'actions',
      width: 80,
      render: (_: unknown, row: Task) => (
        <Tooltip title="Открыть задачу">
          <Button size="small" icon={<EyeOutlined />} onClick={() => navigate(`/tasks/${row.id}`)} />
        </Tooltip>
      ),
    },
  ]

  return (
    <Table
      dataSource={tasks ?? []}
      columns={columns}
      rowKey="id"
      loading={isLoading}
      size="small"
      pagination={{ pageSize: 20 }}
      locale={{ emptyText: 'Задачи не найдены' }}
      expandable={{
        expandedRowRender: (row: Task) => (
          <TaskResultRow taskId={row.id} deviceId={deviceId} />
        ),
      }}
    />
  )
}

// ─── Main page ────────────────────────────────────────────────────────────────

export function DeviceDetailPage() {
  const { id: objIdStr, deviceId: deviceIdStr } = useParams<{ id: string; deviceId: string }>()
  const objId = Number(objIdStr)
  const deviceId = Number(deviceIdStr)
  const navigate = useNavigate()

  const { data: obj } = useObject(objId)
  const { data: device, isLoading } = useDevice(objId, deviceId)
  const { data: tasks } = useDeviceTasks(deviceId)
  const { data: creds, isLoading: credsLoading } = useDeviceCredentials(objId, deviceId)
  const deleteDevice = useDeleteDevice(objId)
  const createTask = useCreateTask()

  const qc = useQueryClient()
  const [editOpen, setEditOpen] = useState(false)
  const [activeTab, setActiveTab] = useState('info')
  const [liveStatus, setLiveStatus] = useState<{ status: string; ping_ms: number | null } | null>(null)

  useMonitorSSE({
    onDeviceStatus: (ev) => {
      if (ev.device_id === deviceId) {
        setLiveStatus({ status: ev.status, ping_ms: ev.ping_ms })
        qc.invalidateQueries({ queryKey: ['device', objId, deviceId] })
      }
    },
  })

  const effectiveStatus = liveStatus?.status ?? device?.status ?? 'unknown'
  const effectivePing = liveStatus !== null ? liveStatus.ping_ms : (device?.last_ping_ms ?? null)
  const webUrl = device ? getDeviceWebUrl(device) : null

  const handleDelete = async () => {
    try {
      await deleteDevice.mutateAsync(deviceId)
      message.success('Устройство удалено')
      navigate(`/inventory/objects/${objId}`)
    } catch {
      message.error('Ошибка при удалении')
    }
  }

  const handlePing = async () => {
    try {
      const task = await createTask.mutateAsync({
        type: 'ping',
        target_scope: { type: 'device', id: deviceId },
        params: {},
      })
      message.success(
        <span>
          Пинг запущен.{' '}
          <a href={`/tasks/${task.id}`} target="_blank" rel="noopener noreferrer">Открыть задачу</a>
        </span>,
        4,
      )
    } catch {
      message.error('Не удалось запустить пинг')
    }
  }

  const handleSystemInfo = async () => {
    try {
      const task = await createTask.mutateAsync({
        type: 'debian_system_info',
        target_scope: { type: 'device', id: deviceId },
        params: {},
      })
      message.success(
        <span>
          Сбор информации запущен.{' '}
          <a href={`/tasks/${task.id}`} target="_blank" rel="noopener noreferrer">Открыть задачу</a>
        </span>,
        4,
      )
    } catch {
      message.error('Не удалось запустить задачу')
    }
  }

  if (isLoading) return <Spin style={{ display: 'block', marginTop: 48 }} />
  if (!device) return (
    <Result
      status="404"
      title="Устройство не найдено"
      extra={<Button onClick={() => navigate(`/inventory/objects/${objId}`)}>К объекту</Button>}
    />
  )

  const isLinuxLike = ['main_server', 'vm', 'embedded', 'other'].includes(device.category)

  const breadcrumbItems = [
    { title: <a onClick={() => navigate('/inventory/objects')}>Инвентарь</a> },
    ...(obj?.city ? [{ title: <a onClick={() => navigate('/inventory/objects')}>{obj.city}</a> }] : []),
    { title: <a onClick={() => navigate(`/inventory/objects/${objId}`)}>{obj?.name ?? `Объект #${objId}`}</a> },
    { title: device.ip },
  ]

  const tabItems = [
    {
      key: 'info',
      label: 'Основное',
      children: (
        <Row gutter={24}>
          <Col xs={24} lg={14}>
            {/* Identity */}
            <Descriptions bordered size="small" column={1} labelStyle={{ width: 180 }}>
              <Descriptions.Item label="IP"><code>{device.ip}</code></Descriptions.Item>
              <Descriptions.Item label="Hostname">{device.hostname ?? '—'}</Descriptions.Item>
              <Descriptions.Item label="MAC">{device.mac ?? '—'}</Descriptions.Item>
              <Descriptions.Item label="Производитель">{device.vendor ?? '—'}</Descriptions.Item>
              <Descriptions.Item label="Модель">{device.model ?? '—'}</Descriptions.Item>
              <Descriptions.Item label="Прошивка">{device.firmware_version ?? '—'}</Descriptions.Item>
              <Descriptions.Item label="Категория"><CategoryTag category={device.category} /></Descriptions.Item>
              <Descriptions.Item label="Роль">{device.role !== 'other' ? device.role : '—'}</Descriptions.Item>
              <Descriptions.Item label="Источник">
                <Tag color={SOURCE_COLOR[device.source] ?? 'default'}>
                  {SOURCE_LABEL[device.source] ?? device.source}
                </Tag>
              </Descriptions.Item>
              <Descriptions.Item label="Активно">
                {device.is_active
                  ? <Tag color="green">Да</Tag>
                  : <Tag color="red">Нет</Tag>}
              </Descriptions.Item>
              {device.external_id && (
                <Descriptions.Item label="External ID">
                  <code>{device.external_id}</code>
                </Descriptions.Item>
              )}
            </Descriptions>

            {/* Location */}
            <Descriptions bordered size="small" column={1} labelStyle={{ width: 180 }} style={{ marginTop: 16 }}>
              <Descriptions.Item label="Объект">
                <a onClick={() => navigate(`/inventory/objects/${objId}`)}>{obj?.name ?? `#${objId}`}</a>
              </Descriptions.Item>
              <Descriptions.Item label="Стойка">
                {device.rack_name
                  ? <Tag color="blue">{device.rack_name}{device.rack_type ? ` ${device.rack_type}` : ''}</Tag>
                  : '—'}
              </Descriptions.Item>
              <Descriptions.Item label="Локация">
                {device.location ? (LOCATION_LABEL[device.location] ?? device.location) : '—'}
              </Descriptions.Item>
            </Descriptions>

            {/* Monitoring */}
            <Descriptions bordered size="small" column={1} labelStyle={{ width: 180 }} style={{ marginTop: 16 }}>
              <Descriptions.Item label="Статус"><DeviceStatusBadge status={effectiveStatus} /></Descriptions.Item>
              <Descriptions.Item label="Последний пинг">
                {(device.last_ping_at ?? device.last_seen) ? (
                  <Tooltip title={elapsedAgo((device.last_ping_at ?? device.last_seen)!)}>
                    <Space size={4} style={{ cursor: 'default' }}>
                      <ClockCircleOutlined style={{ color: '#999' }} />
                      <span>{dayjs(device.last_ping_at ?? device.last_seen).format('DD.MM.YYYY HH:mm:ss')}</span>
                    </Space>
                  </Tooltip>
                ) : '—'}
              </Descriptions.Item>
              <Descriptions.Item label="Онлайн был">
                {device.last_seen ? (
                  <Tooltip title={elapsedAgo(device.last_seen)}>
                    <Space size={4} style={{ cursor: 'default' }}>
                      <ClockCircleOutlined style={{ color: '#52c41a' }} />
                      <span>{dayjs(device.last_seen).format('DD.MM.YYYY HH:mm:ss')}</span>
                    </Space>
                  </Tooltip>
                ) : '—'}
              </Descriptions.Item>
              <Descriptions.Item label="Мониторинг">
                {device.monitor_enabled
                  ? <Tag color="green">Включён</Tag>
                  : <Tag>Выключен</Tag>}
              </Descriptions.Item>
            </Descriptions>

            {/* SSH block — временно скрыт */}

            {/* System info (Linux-like devices) */}
            {isLinuxLike && <SystemInfoBlock device={device} tasks={tasks} />}

            {device.notes && (
              <Card size="small" title="Заметки" style={{ marginTop: 16 }}>
                <Typography.Text>{device.notes}</Typography.Text>
              </Card>
            )}

            <Descriptions bordered size="small" column={2} style={{ marginTop: 16 }}>
              <Descriptions.Item label="Создано">
                <Tooltip title={elapsedAgo(device.created_at)}>
                  {dayjs(device.created_at).format('DD.MM.YYYY HH:mm')}
                </Tooltip>
              </Descriptions.Item>
              <Descriptions.Item label="Обновлено">
                <Tooltip title={elapsedAgo(device.updated_at)}>
                  {dayjs(device.updated_at).format('DD.MM.YYYY HH:mm')}
                </Tooltip>
              </Descriptions.Item>
            </Descriptions>
          </Col>

          <Col xs={24} lg={10}>
            {device.capabilities.length > 0 && (
              <Card size="small" title="Возможности" style={{ marginBottom: 16 }}>
                <Space wrap>
                  {device.capabilities.map((c) => <Tag key={c}>{c}</Tag>)}
                </Space>
              </Card>
            )}
            <DeviceMetaBlock device={device} />
            <ConnectionParamsBlock device={device} creds={creds} credsLoading={credsLoading} />
          </Col>
        </Row>
      ),
    },
    ...(device.category === 'camera' ? [{
      key: 'camera',
      label: 'Камера',
      children: <CameraTab device={device} objId={objId} tasks={tasks} creds={creds} />,
    }] : []),
    {
      key: 'alerts',
      label: 'Алерты',
      children: <AlertsTab deviceId={deviceId} />,
    },
    {
      key: 'snapshots',
      label: 'Снапшоты',
      children: <SnapshotsTab objId={objId} deviceId={deviceId} device={device} />,
    },
    {
      key: 'tasks',
      label: 'История задач',
      children: <TasksTab deviceId={deviceId} />,
    },
  ]

  return (
    <div>
      <Breadcrumb style={{ marginBottom: 16 }} items={breadcrumbItems} />

      <Card style={{ marginBottom: 16 }}>
        <Row justify="space-between" align="top">
          <Col>
            <Space align="baseline" size={12} wrap>
              <Typography.Title level={3} style={{ margin: 0 }}>
                <code>{device.ip}</code>
              </Typography.Title>
              <DeviceStatusBadge status={effectiveStatus} />
              {effectivePing !== null && (
                <Typography.Text type="secondary">{effectivePing}мс</Typography.Text>
              )}
              {!device.is_active && <Tag color="red">Неактивно</Tag>}
            </Space>
            {device.hostname && (
              <div>
                <Typography.Text type="secondary" style={{ fontSize: 14 }}>{device.hostname}</Typography.Text>
              </div>
            )}
            <Space style={{ marginTop: 8 }} wrap>
              <CategoryTag category={device.category} />
              {device.role && device.role !== 'other' && <Tag>{device.role}</Tag>}
              {device.rack_name && <Tag color="blue">{device.rack_name}</Tag>}
              {device.vendor && <Tag color="default">{device.vendor}</Tag>}
              {device.model && <Typography.Text type="secondary" style={{ fontSize: 13 }}>{device.model}</Typography.Text>}
              {device.firmware_version && (
                <Typography.Text type="secondary" style={{ fontSize: 12 }}>
                  <InfoCircleOutlined style={{ marginRight: 4 }} />
                  {device.firmware_version}
                </Typography.Text>
              )}
            </Space>
          </Col>
          <Col>
            <Space wrap>
              {webUrl && (
                <Tooltip title={webUrl}>
                  <Button icon={<LinkOutlined />} href={webUrl} target="_blank" rel="noopener noreferrer">
                    Веб-интерфейс
                  </Button>
                </Tooltip>
              )}
              <Tooltip title="Запустить пинг">
                <Button
                  icon={<ThunderboltOutlined />}
                  loading={createTask.isPending}
                  onClick={handlePing}
                >
                  Пинг
                </Button>
              </Tooltip>
              {isLinuxLike && (
                <Tooltip title="Собрать системную информацию (ОС, RAM, диски)">
                  <Button icon={<InfoCircleOutlined />} onClick={handleSystemInfo}>
                    Sys Info
                  </Button>
                </Tooltip>
              )}
              <Button icon={<EditOutlined />} onClick={() => setEditOpen(true)}>
                Редактировать
              </Button>
              <Popconfirm
                title="Удалить устройство?"
                description="Это действие необратимо."
                okText="Удалить"
                cancelText="Отмена"
                okButtonProps={{ danger: true }}
                onConfirm={handleDelete}
              >
                <Button danger icon={<DeleteOutlined />} loading={deleteDevice.isPending}>
                  Удалить
                </Button>
              </Popconfirm>
            </Space>
          </Col>
        </Row>
      </Card>

      <Card
        tabList={tabItems.map((t) => ({ key: t.key, tab: t.label }))}
        activeTabKey={activeTab}
        onTabChange={setActiveTab}
        bodyStyle={{ paddingTop: 16 }}
      >
        {tabItems.find((t) => t.key === activeTab)?.children}
      </Card>

      <DeviceEditModal
        open={editOpen}
        device={device}
        objId={objId}
        onClose={() => setEditOpen(false)}
      />
    </div>
  )
}
