// frontend/src/pages/devices/DeviceList.jsx

import { useState, useEffect, useCallback } from 'react'
import { useNavigate } from 'react-router-dom'
import api from '@/lib/api'
import { useAuth } from '@/hooks/useAuth'
import PageHeader from '@/components/ui/PageHeader'
import Button from '@/components/ui/Button'
import DataTable from '@/components/ui/DataTable'
import StatusBadge from '@/components/ui/StatusBadge'
import Pagination from '@/components/ui/Pagination'
import SearchBar from '@/components/ui/SearchBar'
import RowActions from '@/components/ui/RowActions'
import Icon from '@/components/ui/Icon'
import SegmentedControl from '@/components/ui/SegmentedControl'
import DeleteDeviceModal from '@/modals/bellcloud/devices/DeleteDeviceModal'
import DeviceFiltersModal from '@/modals/bellcloud/devices/DeviceFiltersModal'
import DeviceListCardView from './DeviceListCardView'
import DeviceListMapView from './DeviceListMapView'

// ─── Column definitions ───────────────────────────────────────────────────────

// Columns marked sortable: name, location, totalBells, assignedUsers, maxOutputs,
// totalPlaybacks, totalHammerStrikes, totalWarnings, totalMelodies
const ALL_COLUMNS = [
  { key: 'status',             label: '',                 pickerLabel: 'Status',         defaultOn: true,  width: '44px' },
  { key: 'name',               label: 'Name',             defaultOn: true,  alwaysOn: true, sortable: true },
  { key: 'serialNumber',       label: 'Serial Number',    defaultOn: true  },
  { key: 'location',           label: 'Location',         defaultOn: true,  sortable: true },
  { key: 'subscrTier',         label: 'Tier',             defaultOn: true  },
  { key: 'totalBells',         label: 'Total Bells',      defaultOn: true,  sortable: true },
  { key: 'assignedUsers',      label: 'Users',            defaultOn: true,  sortable: true },
  { key: 'maxOutputs',         label: 'Max Outputs',      defaultOn: false, sortable: true },
  { key: 'hasClock',           label: 'Has Clock',        defaultOn: false },
  { key: 'hasBells',           label: 'Has Bells',        defaultOn: false },
  { key: 'bellGuard',          label: 'Bell Guard',       defaultOn: false },
  { key: 'warningsOn',         label: 'Warnings On',      defaultOn: false },
  { key: 'serialLogLevel',     label: 'Serial Log Level', defaultOn: false },
  { key: 'sdLogLevel',         label: 'SD Log Level',     defaultOn: false },
  { key: 'bellOutputs',        label: 'Bell Outputs',     defaultOn: false },
  { key: 'hammerTimings',      label: 'Hammer Timings',   defaultOn: false },
  { key: 'ringAlertsMaster',   label: 'Ring Alerts',      defaultOn: false },
  { key: 'totalPlaybacks',     label: 'Playbacks',        defaultOn: false, sortable: true },
  { key: 'totalHammerStrikes', label: 'Hammer Strikes',   defaultOn: false, sortable: true },
  { key: 'totalWarnings',      label: 'Warnings Given',   defaultOn: false, sortable: true },
  { key: 'warrantyActive',     label: 'Warranty',         defaultOn: false },
  { key: 'totalMelodies',      label: 'Melodies',         defaultOn: false, sortable: true },
  { key: 'tags',               label: 'Tags',             defaultOn: false },
  { key: 'hw_family',          label: 'HW Family',        defaultOn: false },
  { key: 'hw_revision',        label: 'HW Revision',      defaultOn: false },
]

const ALL_KEYS = ALL_COLUMNS.map((c) => c.key)

function loadColumnPrefs() {
  try {
    const raw = localStorage.getItem('deviceListColumnPrefs')
    if (raw) {
      const prefs = JSON.parse(raw)
      // prefs = { order: [...keys], visible: [...keys] }
      if (prefs.order && prefs.visible) return prefs
    }
  } catch { /* ignore */ }
  return {
    order:   ALL_KEYS,
    visible: ALL_COLUMNS.filter((c) => c.defaultOn).map((c) => c.key),
  }
}

function saveColumnPrefs(order, visible) {
  try {
    localStorage.setItem('deviceListColumnPrefs', JSON.stringify({ order, visible }))
  } catch { /* ignore */ }
}

// ─── Helpers ──────────────────────────────────────────────────────────────────

function parseFirestoreDate(str) {
  if (!str) return null
  const cleaned = str.replace(' at ', ' ').replace('UTC+0000', 'UTC').replace(/UTC\+\d{4}/, 'UTC')
  const d = new Date(cleaned)
  return isNaN(d.getTime()) ? null : d
}

function isSubscriptionActive(device) {
  const sub = device.device_subscription
  if (!sub?.subscrStart || !sub?.subscrDuration) return false
  try {
    const start = parseFirestoreDate(sub.subscrStart)
    if (!start) return false
    return new Date(start.getTime() + sub.subscrDuration * 86400000) > new Date()
  } catch { return false }
}

function isWarrantyActive(device) {
  const stats = device.device_stats
  if (!stats?.warrantyStart || !stats?.warrantyPeriod) return !!stats?.warrantyActive
  try {
    const start = parseFirestoreDate(stats.warrantyStart)
    if (!start) return !!stats?.warrantyActive
    return new Date(start.getTime() + stats.warrantyPeriod * 86400000) > new Date()
  } catch { return !!stats?.warrantyActive }
}

// ─── Cell sub-components ──────────────────────────────────────────────────────

function OnlineDot({ isOnline }) {
  return (
    <span
      style={{
        display: 'inline-block',
        width: '8px',
        height: '8px',
        borderRadius: 'var(--radius-full)',
        backgroundColor: isOnline ? 'var(--color-success)' : 'var(--color-bg-island)',
        boxShadow: isOnline ? '0 0 6px var(--color-success)' : 'none',
        flexShrink: 0,
      }}
      title={isOnline ? 'Online' : 'Offline'}
      aria-label={isOnline ? 'Online' : 'Offline'}
    />
  )
}

function BoolBadge({ value, yesLabel = 'Yes', noLabel = 'No' }) {
  return (
    <StatusBadge variant={value ? 'success' : 'neutral'} dot={false} size="sm">
      {value ? yesLabel : noLabel}
    </StatusBadge>
  )
}

function TierBadge({ tier }) {
  const t = (tier || 'basic').toLowerCase()
  const variant = t === 'vip' || t === 'premium' ? 'primary' : t === 'custom' ? 'info' : 'neutral'
  return (
    <StatusBadge variant={variant} dot={false} size="sm">
      {t.charAt(0).toUpperCase() + t.slice(1)}
    </StatusBadge>
  )
}

function TagList({ tags }) {
  if (!tags?.length) return <span style={{ color: 'var(--color-text-muted)' }}>—</span>
  return (
    <div style={{ display: 'flex', flexWrap: 'wrap', gap: 'var(--space-1)' }}>
      {tags.map((t) => (
        <StatusBadge key={t} variant="info" dot={false} size="sm">{t}</StatusBadge>
      ))}
    </div>
  )
}

function Muted({ children }) {
  return <span style={{ color: 'var(--color-text-muted)' }}>{children}</span>
}

// ─── Sorting helper ───────────────────────────────────────────────────────────

function getSortValue(device, key) {
  const attr  = device.device_attributes  || {}
  const sub   = device.device_subscription || {}
  const stats = device.device_stats         || {}
  switch (key) {
    case 'name':               return (device.device_name || '').toLowerCase()
    case 'location':           return (device.device_location || '').toLowerCase()
    case 'totalBells':         return attr.totalBells ?? -1
    case 'assignedUsers':      return Array.isArray(device.user_list) ? device.user_list.length : 0
    case 'maxOutputs':         return sub.maxOutputs ?? -1
    case 'totalPlaybacks':     return stats.totalPlaybacks ?? -1
    case 'totalHammerStrikes': return stats.totalHammerStrikes ?? -1
    case 'totalWarnings':      return stats.totalWarningsGiven ?? -1
    case 'totalMelodies':      return device.device_melodies_all?.length ?? -1
    default:                   return 0
  }
}

function sortDevices(devices, key, dir) {
  if (!key) return devices
  return [...devices].sort((a, b) => {
    const va = getSortValue(a, key)
    const vb = getSortValue(b, key)
    if (va < vb) return dir === 'asc' ? -1 : 1
    if (va > vb) return dir === 'asc' ?  1 : -1
    return 0
  })
}

// ─── DeviceList ───────────────────────────────────────────────────────────────

export default function DeviceList() {
  const navigate = useNavigate()
  const { hasPermission } = useAuth()
  const canEdit = hasPermission('devices', 'edit')

  // Data
  const [devices, setDevices] = useState([])
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState('')
  const [mqttStatusMap, setMqttStatusMap] = useState({})
  const [mqttLoaded, setMqttLoaded] = useState(false)

  // Server-side filters
  const [search, setSearch] = useState('')
  const [onlineFilter, setOnlineFilter] = useState('')
  const [tierFilter, setTierFilter] = useState('')

  // Client-side filters
  const [subscrStatusFilter, setSubscrStatusFilter] = useState('')
  const [warrantyStatusFilter, setWarrantyStatusFilter] = useState('')
  const [hasClockFilter, setHasClockFilter] = useState('')
  const [hasBellsFilter, setHasBellsFilter] = useState('')

  // Column prefs (visibility + order)
  const [colPrefs, setColPrefs] = useState(loadColumnPrefs)

  // Sort
  const [sortKey, setSortKey] = useState('')
  const [sortDir, setSortDir] = useState('asc')

  // Pagination
  const [page, setPage] = useState(1)
  const [pageSize, setPageSize] = useState(20)

  // View mode: 'table' | 'card'  (map is temporarily disabled — access via /devices/map-preview)
  const [viewMode, setViewMode] = useState(() => {
    try {
      const saved = localStorage.getItem('deviceListViewMode')
      // Reset 'map' to 'table' while map view is under construction
      return (saved === 'map' ? 'table' : saved) || 'table'
    } catch { return 'table' }
  })

  // Filters modal
  const [filtersOpen, setFiltersOpen] = useState(false)

  // Delete modal
  const [deleteTarget, setDeleteTarget] = useState(null)
  const [deleteError, setDeleteError] = useState('')

  // ── Column change handler ──────────────────────────────────────────────────
  // Accepts either a new visible array (from toggle) or a new order array (from drag)
  // DataTable calls onColumnChange with the new visibleKeys array for both operations
  const handleColumnChange = useCallback((newVisibleKeys) => {
    setColPrefs((prev) => {
      // Detect if this is a reorder (same keys, different order) or visibility toggle
      const sortedPrev = [...prev.visible].sort()
      const sortedNext = [...newVisibleKeys].sort()
      const isReorder = JSON.stringify(sortedPrev) === JSON.stringify(sortedNext)

      let nextOrder   = prev.order
      let nextVisible = prev.visible

      if (isReorder) {
        // Drag reorder: update the order of visible keys, keeping hidden keys appended
        const hiddenKeys = prev.order.filter((k) => !prev.visible.includes(k))
        nextOrder   = [...newVisibleKeys, ...hiddenKeys]
        nextVisible = newVisibleKeys
      } else {
        // Visibility toggle: preserve order, just update visible set
        nextVisible = newVisibleKeys
      }

      saveColumnPrefs(nextOrder, nextVisible)
      return { order: nextOrder, visible: nextVisible }
    })
  }, [])

  // ── Fetch devices ──────────────────────────────────────────────────────────
  const fetchDevices = useCallback(async () => {
    setLoading(true)
    setMqttLoaded(false)
    setError('')
    try {
      const params = new URLSearchParams()
      if (search) params.set('search', search)
      if (onlineFilter === 'true')  params.set('online', 'true')
      if (onlineFilter === 'false') params.set('online', 'false')
      if (tierFilter) params.set('tier', tierFilter)
      // Note: online filter is server-side — we pass it as a query param but
      // the server returns ALL devices when the param is absent, so we also
      // apply a client-side guard to ensure ONLINE-only actually filters.
      const qs = params.toString()
      const data = await api.get(`/devices${qs ? `?${qs}` : ''}`)
      setDevices(data.devices ?? [])
      api.get('/mqtt/status').then((mqttData) => {
        if (mqttData?.devices) {
          const map = {}
          for (const s of mqttData.devices) map[s.device_serial] = s
          setMqttStatusMap(map)
        }
        setMqttLoaded(true)
      }).catch(() => { setMqttLoaded(true) })
    } catch (err) {
      setError(err.message || 'Failed to load devices.')
    } finally {
      setLoading(false)
    }
  }, [search, onlineFilter, tierFilter])

  useEffect(() => { fetchDevices() }, [fetchDevices])

  useEffect(() => {
    setPage(1)
  }, [search, onlineFilter, tierFilter, subscrStatusFilter, warrantyStatusFilter, hasClockFilter, hasBellsFilter])

  // ── Delete ─────────────────────────────────────────────────────────────────
  const handleDelete = async () => {
    if (!deleteTarget) return
    setDeleteError('')
    try {
      await api.delete(`/devices/${deleteTarget.id}`)
      setDeleteTarget(null)
      fetchDevices()
    } catch (err) {
      setDeleteError(err.message || 'Failed to delete device.')
    }
  }

  // ── Client-side filtering + sorting ───────────────────────────────────────
  const filteredDevices = devices.filter((device) => {
    // Online/offline — wait for MQTT data before applying so we don't show
    // false-negative "no devices" while the status map is still loading.
    const sn = device.serial_number || device.device_id
    const mqtt = mqttStatusMap[sn]
    const isOnline = mqtt ? mqtt.online : (device.is_Online ?? false)
    // Only apply online/offline filter once MQTT status has resolved —
    // prevents false-negative empty table while the status map is still loading.
    if (onlineFilter === 'true'  && mqttLoaded && !isOnline) return false
    if (onlineFilter === 'false' && mqttLoaded &&  isOnline) return false

    if (subscrStatusFilter === 'active'  && !isSubscriptionActive(device)) return false
    if (subscrStatusFilter === 'expired' && isSubscriptionActive(device))  return false
    if (warrantyStatusFilter === 'active'  && !isWarrantyActive(device)) return false
    if (warrantyStatusFilter === 'expired' && isWarrantyActive(device))  return false
    if (hasClockFilter === 'yes' && !device.device_attributes?.hasClock) return false
    if (hasClockFilter === 'no'  && device.device_attributes?.hasClock)  return false
    if (hasBellsFilter === 'yes' && !device.device_attributes?.hasBells) return false
    if (hasBellsFilter === 'no'  && device.device_attributes?.hasBells)  return false
    return true
  })

  const sortedDevices  = sortDevices(filteredDevices, sortKey, sortDir)
  const total          = sortedDevices.length
  const pagedDevices   = sortedDevices.slice((page - 1) * pageSize, page * pageSize)

  // ── Active filter count (for badge on Filters button) ─────────────────────
  const activeFilterCount = [onlineFilter, tierFilter, subscrStatusFilter, warrantyStatusFilter, hasClockFilter, hasBellsFilter].filter(Boolean).length

  // ── Middle-click handler ───────────────────────────────────────────────────
  const handleRowMiddleClick = (device, e) => {
    if (e.button === 1) {
      e.preventDefault()
      window.open(`/devices/${device.id}`, '_blank', 'noopener,noreferrer')
    }
  }

  // ── Build DataTable column definitions ────────────────────────────────────
  // Respect the saved column order
  const orderedVisible = colPrefs.order.filter((k) => colPrefs.visible.includes(k))

  const tableColumns = orderedVisible
    .map((key) => {
      const c = ALL_COLUMNS.find((col) => col.key === key)
      if (!c) return null
      return {
        key: c.key,
        label: c.label,
        width: c.width,
        sortable: c.sortable,
        render: (device) => {
          const attr  = device.device_attributes   || {}
          const clock = attr.clockSettings          || {}
          const sub   = device.device_subscription  || {}
          const stats = device.device_stats          || {}
          const sn    = device.serial_number || device.device_id
          const mqtt  = mqttStatusMap[sn]
          const isOnline = mqtt ? mqtt.online : device.is_Online

          switch (c.key) {
            case 'status':
              return <OnlineDot isOnline={isOnline} />
            case 'name':
              return (
                <span style={{ fontWeight: 'var(--font-weight-medium)', color: 'var(--color-text-primary)' }}>
                  {device.device_name || 'Unnamed Device'}
                </span>
              )
            case 'serialNumber':
              return (
                <span style={{ fontFamily: 'var(--font-family-mono)', color: 'var(--color-text-muted)', fontSize: 'var(--font-size-sm)' }}>
                  {sn || '—'}
                </span>
              )
            case 'location':
              return device.device_location || <Muted>—</Muted>
            case 'subscrTier':
              return <TierBadge tier={sub.subscrTier} />
            case 'totalBells':
              return attr.totalBells ?? 0
            case 'assignedUsers':
              return Array.isArray(device.user_list) ? device.user_list.length : 0
            case 'maxOutputs':
              return sub.maxOutputs ?? <Muted>—</Muted>
            case 'hasClock':
              return <BoolBadge value={attr.hasClock} />
            case 'hasBells':
              return <BoolBadge value={attr.hasBells} />
            case 'bellGuard':
              return <BoolBadge value={attr.bellGuardOn} />
            case 'warningsOn':
              return <BoolBadge value={attr.warningsOn} />
            case 'serialLogLevel':
              return attr.serialLogLevel ?? 0
            case 'sdLogLevel':
              return attr.sdLogLevel ?? 0
            case 'bellOutputs':
              return attr.bellOutputs?.length ? attr.bellOutputs.join(', ') : <Muted>—</Muted>
            case 'hammerTimings':
              return attr.hammerTimings?.length ? attr.hammerTimings.join(', ') : <Muted>—</Muted>
            case 'ringAlertsMaster':
              return <BoolBadge value={clock.ringAlertsMasterOn} yesLabel="ON" noLabel="OFF" />
            case 'totalPlaybacks':
              return stats.totalPlaybacks ?? 0
            case 'totalHammerStrikes':
              return stats.totalHammerStrikes ?? 0
            case 'totalWarnings':
              return stats.totalWarningsGiven ?? 0
            case 'warrantyActive':
              return <BoolBadge value={stats.warrantyActive} yesLabel="Active" noLabel="Expired" />
            case 'totalMelodies':
              return device.device_melodies_all?.length ?? 0
            case 'tags':
              return <TagList tags={device.tags} />
            case 'hw_family':
              return device.hw_family  || <Muted>—</Muted>
            case 'hw_revision':
              return device.hw_revision || <Muted>—</Muted>
            default:
              return <Muted>—</Muted>
          }
        },
      }
    })
    .filter(Boolean)

  // Actions column (not part of ALL_COLUMNS — appended, never draggable)
  tableColumns.push({
    key: '__actions',
    label: '',
    width: '110px',
    align: 'right',
    render: (device) => (
      <div onClick={(e) => e.stopPropagation()} style={{ display: 'flex', justifyContent: 'flex-end' }}>
        <RowActions
          actions={[
            {
              label: 'View Details',
              icon: <Icon name="eye" size={14} />,
              onClick: () => navigate(`/devices/${device.id}`),
            },
            ...(canEdit ? [
              {
                label: 'Edit',
                icon: <Icon name="edit" size={14} />,
                color: 'var(--color-info)',
                onClick: () => navigate(`/devices/${device.id}/edit`),
              },
              {
                label: 'Delete',
                icon: <Icon name="delete" size={14} />,
                color: 'var(--color-danger)',
                divider: true,
                onClick: () => { setDeleteError(''); setDeleteTarget(device) },
              },
            ] : []),
          ]}
        />
      </div>
    ),
  })

  // ─────────────────────────────────────────────────────────────────────────

  return (
    <div className="page-wrapper">

      {/* Page header */}
      <PageHeader
        title="Device Fleet"
        subtitle={!loading
          ? `${filteredDevices.length} ${filteredDevices.length === 1 ? 'device' : 'devices'}`
          : undefined
        }
      >
        {canEdit && (
          <Button variant="primary" onClick={() => navigate('/devices/new')}>
            Add Device
          </Button>
        )}
      </PageHeader>

      {/* Toolbar + pagination + content — single tight-gap column so all three
          items are visually grouped and equidistant from each other */}
      <div style={{ display: 'flex', flexDirection: 'column', gap: 'var(--space-3)', minWidth: 0 }}>

        {/* Filter toolbar */}
        <div style={{ display: 'flex', flexWrap: 'wrap', gap: 'var(--space-3)', alignItems: 'center', minWidth: 0 }}>

          <div style={{ flex: '1 1 0', minWidth: '180px' }}>
            <SearchBar
              value={search}
              onChange={setSearch}
              placeholder="Search by name, location, or serial…"
            />
          </div>

          <Button
            variant={activeFilterCount > 0 ? 'secondary' : 'ghost'}
            size="md"
            onClick={() => setFiltersOpen(true)}
            style={{ paddingTop: 'var(--space-3)', paddingBottom: 'var(--space-3)', lineHeight: 'var(--line-height-base)' }}
            icon={
              <svg width="14" height="14" viewBox="0 0 24 24" fill="none"
                stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
                <polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3"/>
              </svg>
            }
          >
            Filters{activeFilterCount > 0 ? ` (${activeFilterCount})` : ''}
          </Button>

          <SegmentedControl
            options={[
              { value: 'table', label: 'Table', icon: <Icon name="more_horizontal" size={14} /> },
              { value: 'card',  label: 'Cards', icon: <Icon name="dashboard"       size={14} /> },
              // Map option temporarily hidden — access via /devices/map-preview while under construction
            ]}
            value={viewMode}
            onChange={(v) => {
              setViewMode(v)
              try { localStorage.setItem('deviceListViewMode', v) } catch { /* ignore */ }
            }}
            size="md"
            style={{ flexShrink: 0 }}
          />

        </div>

        {/* Error banner */}
        {error && (
          <div
            role="alert"
            style={{
              backgroundColor: 'var(--color-danger-bg)',
              border: '1px solid var(--color-danger-container)',
              borderRadius: 'var(--radius-md)',
              padding: 'var(--space-3) var(--space-4)',
              color: 'var(--color-danger)',
              fontSize: 'var(--font-size-sm)',
            }}
          >
            {error}
          </div>
        )}

        {total > 0 && viewMode !== 'map' && (
          <Pagination
            page={page}
            pageSize={pageSize}
            total={total}
            onPageChange={setPage}
            onSizeChange={(s) => { setPageSize(s); setPage(1) }}
            pageSizes={[10, 20, 50, 100]}
          />
        )}

        {/* Table, Card, or Map view */}
        {viewMode === 'map' ? (
          <DeviceListMapView
            devices={filteredDevices}
            loading={loading}
            mqttStatusMap={mqttStatusMap}
            onView={(device) => navigate(`/devices/${device.id}`)}
          />
        ) : viewMode === 'card' ? (
          <DeviceListCardView
            devices={pagedDevices}
            loading={loading}
            mqttStatusMap={mqttStatusMap}
            onView={(device) => navigate(`/devices/${device.id}`)}
            onMiddleClick={(device, e) => handleRowMiddleClick(device, e)}
          />
        ) : (
          <DataTable
            columns={tableColumns}
            data={pagedDevices}
            loading={loading}
            keyField="id"
            emptyMessage="No devices found"
            emptyDescription="Try adjusting your search or filters."
            onRowClick={(device) => navigate(`/devices/${device.id}`)}
            onRowMiddleClick={(device, e) => handleRowMiddleClick(device, e)}
            skeletonRows={8}
            sortKey={sortKey}
            sortDir={sortDir}
            onSort={(key, dir) => { setSortKey(key); setSortDir(dir); setPage(1) }}
            allColumns={ALL_COLUMNS}
            visibleKeys={colPrefs.visible}
            onColumnChange={handleColumnChange}
          />
        )}

      </div>

      {/* Filters modal */}
      <DeviceFiltersModal
        open={filtersOpen}
        onClose={() => setFiltersOpen(false)}
        onlineFilter={onlineFilter}           setOnlineFilter={setOnlineFilter}
        tierFilter={tierFilter}               setTierFilter={setTierFilter}
        subscrStatusFilter={subscrStatusFilter} setSubscrStatusFilter={setSubscrStatusFilter}
        warrantyStatusFilter={warrantyStatusFilter} setWarrantyStatusFilter={setWarrantyStatusFilter}
        hasClockFilter={hasClockFilter}       setHasClockFilter={setHasClockFilter}
        hasBellsFilter={hasBellsFilter}       setHasBellsFilter={setHasBellsFilter}
      />

      {/* Delete confirmation modal */}
      <DeleteDeviceModal
        device={deleteTarget}
        onConfirm={handleDelete}
        onCancel={() => { setDeleteTarget(null); setDeleteError('') }}
        error={deleteError}
      />

    </div>
  )
}
