// frontend/src/pages/manufacturing/firmware/FirmwareManager.jsx
// Firmware Files tab — uses DataTable with column reorder, RowActions, Select

import { useState, useEffect, useRef } from 'react'
import { createPortal } from 'react-dom'
import api from '@/lib/api'
import { useAuth } from '@/hooks/useAuth'
import Button from '@/components/ui/Button'
import StatusBadge from '@/components/ui/StatusBadge'
import Spinner from '@/components/ui/Spinner'
import Modal from '@/components/ui/Modal'
import FormField from '@/components/ui/FormField'
import Select from '@/components/ui/Select'
import ConfirmDialog from '@/components/ui/ConfirmDialog'
import SearchBar from '@/components/ui/SearchBar'
import { fmtDateTimeMedium } from '@/lib/formatters'
import DataTable from '@/components/ui/DataTable'
import RowActions from '@/components/ui/RowActions'

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

const BOARD_TYPES = [
  { value: 'vesper',      label: 'Vesper'      },
  { value: 'vesper_plus', label: 'Vesper+'     },
  { value: 'vesper_pro',  label: 'Vesper Pro'  },
  { value: 'chronos',     label: 'Chronos'     },
  { value: 'chronos_pro', label: 'Chronos Pro' },
  { value: 'agnus',       label: 'Agnus'       },
  { value: 'agnus_mini',  label: 'Agnus Mini'  },
  { value: 'bespoke',     label: 'Bespoke'     },
]

const BOARD_TYPE_LABELS = Object.fromEntries(BOARD_TYPES.map((b) => [b.value, b.label]))
const CHANNELS = ['stable', 'beta', 'alpha', 'testing']

const CHANNEL_VARIANT = { stable: 'success', beta: 'info', alpha: 'warning', testing: 'neutral' }
const UPDATE_TYPE_VARIANT = { mandatory: 'info', emergency: 'danger', optional: 'neutral' }

// ─── All columns definition ───────────────────────────────────────────────────

const ALL_COLUMNS = [
  { key: 'hw_type',     label: 'Type',         sortable: true,  alwaysOn: true },
  { key: 'channel',     label: 'Channel',      sortable: true  },
  { key: 'version',     label: 'Version',      sortable: true  },
  { key: 'update_type', label: 'Update Type',  sortable: true  },
  { key: 'min_fw',      label: 'Min FW'                        },
  { key: 'size',        label: 'Size'                          },
  { key: 'sha256',      label: 'SHA-256'                       },
  { key: 'notes',       label: 'Release Note'                  },
  { key: 'uploaded_at', label: 'Uploaded',     sortable: true  },
  { key: 'is_latest',   label: 'Latest'                        },
  { key: '__actions',   label: '',             align: 'right'  },
]

const DEFAULT_VISIBLE = ['hw_type', 'channel', 'version', 'update_type', 'min_fw', 'size', 'notes', 'uploaded_at', 'is_latest', '__actions']
const COLS_KEY  = 'fw_manager_visible_v2'
const ORDER_KEY = 'fw_manager_order_v2'

function loadColPrefs() {
  try {
    const vis   = JSON.parse(localStorage.getItem(COLS_KEY))
    const order = JSON.parse(localStorage.getItem(ORDER_KEY))
    return {
      visible: Array.isArray(vis)   ? vis   : DEFAULT_VISIBLE,
      order:   Array.isArray(order) ? order : DEFAULT_VISIBLE,
    }
  } catch {
    return { visible: DEFAULT_VISIBLE, order: DEFAULT_VISIBLE }
  }
}

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

function formatBytes(bytes) {
  if (!bytes) return '—'
  if (bytes < 1024) return `${bytes} B`
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`
  return `${(bytes / (1024 * 1024)).toFixed(2)} MB`
}

function formatDate(iso) { return fmtDateTimeMedium(iso) }

// ─── Changelog modal ──────────────────────────────────────────────────────────

function ChangelogModal({ fw, onClose }) {
  return (
    <Modal open={!!fw} onClose={onClose} title={fw ? `Changelog — ${fw.hw_type} v${fw.version} (${fw.channel})` : ''} size="md">
      {fw?.changelog ? (
        <p style={{ fontSize: 'var(--font-size-sm)', color: 'var(--color-text-secondary)', whiteSpace: 'pre-wrap', lineHeight: 1.6 }}>
          {fw.changelog}
        </p>
      ) : (
        <p style={{ fontSize: 'var(--font-size-sm)', color: 'var(--color-text-muted)', fontStyle: 'italic' }}>
          No changelog for this version.
        </p>
      )}
    </Modal>
  )
}

// ─── Upload / Edit modal ──────────────────────────────────────────────────────

function FirmwareFormModal({ initial, onClose, onSaved }) {
  const isEdit = !!initial

  const [hwType,      setHwType]      = useState(initial?.hw_type       ?? 'vesper')
  const [bespokeUid,  setBespokeUid]  = useState(initial?.bespoke_uid   ?? '')
  const [channel,     setChannel]     = useState(initial?.channel       ?? 'stable')
  const [version,     setVersion]     = useState(initial?.version       ?? '')
  const [updateType,  setUpdateType]  = useState(initial?.update_type   ?? 'mandatory')
  const [minFw,       setMinFw]       = useState(initial?.min_fw_version ?? '')
  const [changelog,   setChangelog]   = useState(initial?.changelog     ?? '')
  const [releaseNote, setReleaseNote] = useState(initial?.release_note  ?? '')
  const [file,        setFile]        = useState(null)
  const [uploading,   setUploading]   = useState(false)
  const [error,       setError]       = useState('')
  const fileInputRef = useRef(null)

  const handleSubmit = async (e) => {
    e.preventDefault()
    if (!isEdit && !file) { setError('A .bin file is required.'); return }
    if (hwType === 'bespoke' && !bespokeUid.trim()) { setError('Bespoke UID is required.'); return }
    setError(''); setUploading(true)
    try {
      const fd = new FormData()
      if (!isEdit) {
        fd.append('hw_type', hwType); fd.append('channel', channel)
        fd.append('version', version); fd.append('update_type', updateType)
        if (minFw) fd.append('min_fw_version', minFw)
        fd.append('changelog', changelog); fd.append('release_note', releaseNote)
        if (hwType === 'bespoke') fd.append('bespoke_uid', bespokeUid.trim())
        fd.append('file', file)
      } else {
        fd.append('channel', channel); fd.append('version', version)
        fd.append('update_type', updateType); fd.append('min_fw_version', minFw)
        fd.append('changelog', changelog); fd.append('release_note', releaseNote)
        if (hwType === 'bespoke') fd.append('bespoke_uid', bespokeUid.trim())
        if (file) fd.append('file', file)
      }
      const token  = localStorage.getItem('access_token')
      const url    = isEdit ? `/api/firmware/${initial.id}` : '/api/firmware/upload'
      const method = isEdit ? 'PUT' : 'POST'
      const res    = await fetch(url, { method, headers: { Authorization: `Bearer ${token}` }, body: fd })
      if (!res.ok) {
        const err = await res.json().catch(() => ({}))
        throw new Error(err.detail || (isEdit ? 'Update failed' : 'Upload failed'))
      }
      onSaved()
    } catch (err) {
      setError(err.message)
    } finally {
      setUploading(false)
    }
  }

  const UPDATE_TYPES = [
    { value: 'mandatory', label: 'Mandatory', desc: 'Auto on reboot',  colorVar: 'info'    },
    { value: 'emergency', label: 'Emergency', desc: 'Immediate push',  colorVar: 'danger'  },
    { value: 'optional',  label: 'Optional',  desc: 'User-initiated',  colorVar: 'success' },
  ]

  return (
    <Modal
      open
      onClose={onClose}
      title={isEdit ? 'Edit Release' : 'Upload Firmware Release'}
      size="xl"
      footer={
        <div style={{ display: 'flex', gap: 'var(--space-3)', justifyContent: 'flex-end' }}>
          <Button variant="ghost" onClick={onClose}>Cancel</Button>
          <Button variant="primary" onClick={handleSubmit} loading={uploading}>
            {isEdit ? 'Save Changes' : 'Upload Firmware'}
          </Button>
        </div>
      }
    >
      <form onSubmit={handleSubmit} style={{ display: 'flex', flexDirection: 'column', gap: 'var(--space-4)' }}>
        {error && (
          <div style={{ padding: 'var(--space-3)', borderRadius: 'var(--radius-md)', backgroundColor: 'var(--color-danger-bg)', border: '1px solid var(--color-danger)', color: 'var(--color-danger)', fontSize: 'var(--font-size-sm)' }}>
            {error}
          </div>
        )}
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 'var(--space-6)' }}>
          {/* Left: config */}
          <div style={{ display: 'flex', flexDirection: 'column', gap: 'var(--space-4)' }}>
            <FormField label="Board Type" name="hw_type" type="select" value={hwType} onChange={(e) => setHwType(e.target.value)} disabled={isEdit} hint={isEdit ? 'Cannot be changed after upload.' : undefined}>
              {BOARD_TYPES.map((bt) => <option key={bt.value} value={bt.value}>{bt.label}</option>)}
            </FormField>
            {hwType === 'bespoke' && (
              <FormField label="Bespoke UID" name="bespoke_uid" value={bespokeUid} onChange={(e) => setBespokeUid(e.target.value)} placeholder="e.g. client-athens-v1" disabled={isEdit} required />
            )}
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 'var(--space-2)' }}>
              <FormField label="Channel" name="channel" type="select" value={channel} onChange={(e) => setChannel(e.target.value)}>
                {CHANNELS.map((c) => <option key={c} value={c}>{c}</option>)}
              </FormField>
              <FormField label="Version" name="version" value={version} onChange={(e) => setVersion(e.target.value)} placeholder="1.5" required />
              <FormField label="Min FW" name="min_fw" value={minFw} onChange={(e) => setMinFw(e.target.value)} placeholder="e.g. 1.2" />
            </div>
            <div>
              <p style={{ fontSize: 'var(--font-size-xs)', fontWeight: 'var(--font-weight-medium)', color: 'var(--color-text-muted)', marginBottom: 'var(--space-2)' }}>Update Type</p>
              <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 'var(--space-2)' }}>
                {UPDATE_TYPES.map((opt) => {
                  const active = updateType === opt.value
                  return (
                    <button key={opt.value} type="button" onClick={() => setUpdateType(opt.value)} style={{
                      padding: 'var(--space-2)', borderRadius: 'var(--radius-md)',
                      border: `1px solid ${active ? `var(--color-${opt.colorVar})` : 'var(--color-border)'}`,
                      backgroundColor: active ? `var(--color-${opt.colorVar}-bg)` : 'var(--color-bg-elevated)',
                      color: active ? `var(--color-${opt.colorVar})` : 'var(--color-text-muted)',
                      cursor: 'pointer', textAlign: 'center',
                    }}>
                      <div style={{ fontSize: 'var(--font-size-xs)', fontWeight: 'var(--font-weight-semibold)' }}>{opt.label}</div>
                      <div style={{ fontSize: 'var(--font-size-xs)', opacity: 0.7, marginTop: 2 }}>{opt.desc}</div>
                    </button>
                  )
                })}
              </div>
            </div>
          </div>

          {/* Middle: changelog */}
          <div style={{ display: 'flex', flexDirection: 'column' }}>
            <FormField label="Changelog" name="changelog" type="textarea" value={changelog} onChange={(e) => setChangelog(e.target.value)}
              placeholder={'Full changelog — describe what changed, bugs fixed, new features, etc.\n\nLike the body of a commit message.'}
              style={{ flex: 1, minHeight: '200px' }} />
          </div>

          {/* Right: release note + file */}
          <div style={{ display: 'flex', flexDirection: 'column', gap: 'var(--space-4)' }}>
            <FormField label="Release Note" name="release_note" value={releaseNote} onChange={(e) => setReleaseNote(e.target.value)}
              placeholder="e.g. Fixed bell timing bug" maxLength={120} hint="Shown in the table and served with OTA metadata." />
            <div style={{ flex: 1, display: 'flex', flexDirection: 'column' }}>
              <p style={{ fontSize: 'var(--font-size-xs)', fontWeight: 'var(--font-weight-medium)', color: 'var(--color-text-muted)', marginBottom: 'var(--space-2)' }}>
                File Upload {isEdit && <span style={{ opacity: 0.7 }}>(leave empty to keep existing)</span>}
              </p>
              <div
                onClick={() => fileInputRef.current?.click()}
                onDragOver={(e) => e.preventDefault()}
                onDrop={(e) => {
                  e.preventDefault()
                  const f = e.dataTransfer.files[0]
                  if (f && f.name.endsWith('.bin')) setFile(f)
                  else if (f) setError('Only .bin files are accepted.')
                }}
                style={{
                  flex: 1, display: 'flex', flexDirection: 'column',
                  alignItems: 'center', justifyContent: 'center', gap: 'var(--space-2)',
                  border: `2px dashed ${file ? 'var(--color-primary)' : 'var(--color-border)'}`,
                  borderRadius: 'var(--radius-lg)',
                  backgroundColor: file ? 'var(--color-info-bg)' : 'var(--color-bg-elevated)',
                  cursor: 'pointer', padding: 'var(--space-4)', minHeight: '100px',
                }}
              >
                <input ref={fileInputRef} type="file" accept=".bin"
                  onChange={(e) => {
                    const f = e.target.files[0]
                    if (f && !f.name.endsWith('.bin')) { setError('Only .bin files are accepted.'); return }
                    setFile(f || null)
                  }}
                  style={{ display: 'none' }} />
                {file ? (
                  <>
                    <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="var(--color-primary)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><polyline points="20 6 9 17 4 12" /></svg>
                    <span style={{ fontSize: 'var(--font-size-xs)', fontWeight: 'var(--font-weight-semibold)', color: 'var(--color-info)', wordBreak: 'break-all', textAlign: 'center' }}>{file.name}</span>
                    <span style={{ fontSize: 'var(--font-size-xs)', color: 'var(--color-text-muted)' }}>{formatBytes(file.size)}</span>
                  </>
                ) : (
                  <>
                    <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="var(--color-text-muted)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
                      <line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/>
                    </svg>
                    <span style={{ fontSize: 'var(--font-size-xs)', color: 'var(--color-text-muted)', textAlign: 'center' }}>Click or drop <strong>.bin</strong> file</span>
                  </>
                )}
              </div>
            </div>
          </div>
        </div>
      </form>
    </Modal>
  )
}

// ─── Main component ───────────────────────────────────────────────────────────

export default function FirmwareManager() {
  const { hasPermission } = useAuth()
  const canAdd    = hasPermission('manufacturing', 'add')
  const canDelete = hasPermission('manufacturing', 'delete')

  const [firmware,      setFirmware]      = useState([])
  const [loading,       setLoading]       = useState(true)
  const [error,         setError]         = useState('')
  const [hwTypeFilter,  setHwTypeFilter]  = useState('')
  const [channelFilter, setChannelFilter] = useState('')
  const [search,        setSearch]        = useState('')
  const [sortKey,       setSortKey]       = useState('uploaded_at')
  const [sortDir,       setSortDir]       = useState('desc')

  const [colPrefs, setColPrefs] = useState(loadColPrefs)

  const [showUpload,   setShowUpload]   = useState(false)
  const [editTarget,   setEditTarget]   = useState(null)
  const [deleteTarget, setDeleteTarget] = useState(null)
  const [deleting,     setDeleting]     = useState(false)
  const [changelogFw,  setChangelogFw]  = useState(null)

  const handleColChange = (nextVisible) => {
    // nextVisible is the new ordered+visible array from DataTable drag reorder
    const nextPrefs = { visible: nextVisible, order: nextVisible }
    setColPrefs(nextPrefs)
    localStorage.setItem(COLS_KEY,  JSON.stringify(nextVisible))
    localStorage.setItem(ORDER_KEY, JSON.stringify(nextVisible))
  }

  const fetchFirmware = async () => {
    setLoading(true); setError('')
    try {
      const params = new URLSearchParams()
      if (hwTypeFilter)  params.set('hw_type', hwTypeFilter)
      if (channelFilter) params.set('channel', channelFilter)
      const qs   = params.toString()
      const data = await api.get(`/firmware${qs ? `?${qs}` : ''}`)
      setFirmware(data.firmware)
    } catch (err) {
      setError(err.message)
    } finally {
      setLoading(false)
    }
  }

  useEffect(() => { fetchFirmware() }, [hwTypeFilter, channelFilter])

  const handleDelete = async () => {
    if (!deleteTarget) return
    setDeleting(true)
    try {
      await api.delete(`/firmware/${deleteTarget.id}`)
    } catch (err) {
      setError(err.message)
    } finally {
      setDeleteTarget(null); setDeleting(false)
      await fetchFirmware()
    }
  }

  // Filter + search + sort
  const filteredFirmware = firmware
    .filter((fw) => {
      if (!search) return true
      const q = search.toLowerCase()
      return (
        (fw.hw_type      || '').toLowerCase().includes(q) ||
        (fw.channel      || '').toLowerCase().includes(q) ||
        (fw.version      || '').toLowerCase().includes(q) ||
        (fw.update_type  || '').toLowerCase().includes(q) ||
        (fw.changelog    || '').toLowerCase().includes(q) ||
        (fw.release_note || '').toLowerCase().includes(q)
      )
    })
    .sort((a, b) => {
      const dir = sortDir === 'asc' ? 1 : -1
      if (sortKey === 'hw_type')     return dir * (a.hw_type     || '').localeCompare(b.hw_type     || '')
      if (sortKey === 'channel')     return dir * (a.channel     || '').localeCompare(b.channel     || '')
      if (sortKey === 'version')     return dir * (a.version     || '').localeCompare(b.version     || '')
      if (sortKey === 'update_type') return dir * (a.update_type || '').localeCompare(b.update_type || '')
      if (sortKey === 'uploaded_at') return dir * ((a.uploaded_at || '') < (b.uploaded_at || '') ? -1 : 1)
      return 0
    })

  // Build columns for DataTable based on current visible order
  const { visible: visibleKeys } = colPrefs
  const columns = visibleKeys
    .map((k) => ALL_COLUMNS.find((c) => c.key === k))
    .filter(Boolean)
    .map((col) => ({ ...col, render: (fw) => renderCell(col, fw) }))

  function renderCell(col, fw) {
    switch (col.key) {
      case 'hw_type': return (
        <div>
          <span style={{ color: 'var(--color-text-secondary)', fontWeight: 'var(--font-weight-semibold)' }}>
            {BOARD_TYPE_LABELS[fw.hw_type] || fw.hw_type}
          </span>
          {fw.bespoke_uid && (
            <div style={{ fontFamily: 'var(--font-family-mono)', fontSize: 'var(--font-size-xs)', color: 'var(--color-text-muted)', marginTop: 2 }}>
              {fw.bespoke_uid}
            </div>
          )}
        </div>
      )
      case 'channel':     return <StatusBadge variant={CHANNEL_VARIANT[fw.channel] || 'neutral'}>{fw.channel}</StatusBadge>
      case 'version':     return <span style={{ fontFamily: 'var(--font-family-mono)', fontSize: 'var(--font-size-xs)', color: 'var(--color-text-primary)' }}>{fw.version}</span>
      case 'update_type': return <StatusBadge variant={UPDATE_TYPE_VARIANT[fw.update_type] || 'neutral'}>{fw.update_type}</StatusBadge>
      case 'min_fw':      return <span style={{ fontFamily: 'var(--font-family-mono)', fontSize: 'var(--font-size-xs)', color: 'var(--color-text-muted)' }}>{fw.min_fw_version || '—'}</span>
      case 'size':        return <span style={{ fontSize: 'var(--font-size-xs)', color: 'var(--color-text-muted)' }}>{formatBytes(fw.size_bytes)}</span>
      case 'sha256':      return (
        <span style={{ fontFamily: 'var(--font-family-mono)', fontSize: 'var(--font-size-xs)', color: 'var(--color-text-muted)' }} title={fw.sha256}>
          {fw.sha256 ? fw.sha256.slice(0, 12) + '…' : '—'}
        </span>
      )
      case 'notes': return (
        <span style={{ fontSize: 'var(--font-size-xs)', color: 'var(--color-text-secondary)', maxWidth: 240, display: 'block', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }} title={fw.release_note || ''}>
          {fw.release_note || <span style={{ color: 'var(--color-text-muted)', fontStyle: 'italic' }}>—</span>}
        </span>
      )
      case 'uploaded_at': return <span style={{ fontSize: 'var(--font-size-xs)', color: 'var(--color-text-muted)' }}>{formatDate(fw.uploaded_at)}</span>
      case 'is_latest':   return fw.is_latest ? <StatusBadge variant="success">latest</StatusBadge> : null
      case '__actions': {
        const actions = [
          { label: 'View Changelog', onClick: () => setChangelogFw(fw) },
          { label: 'Copy .bin URL',  onClick: () => {
            const url = `${window.location.origin}/api/firmware/${fw.hw_type}/${fw.channel}/${fw.version}/firmware.bin`
            navigator.clipboard.writeText(url).catch(() => {})
          }},
          ...(canAdd    ? [{ label: 'Edit Release',   onClick: () => setEditTarget(fw),   divider: true }] : []),
          ...(canDelete ? [{ label: 'Delete Release', onClick: () => setDeleteTarget(fw), color: 'var(--color-danger)' }] : []),
        ]
        return <RowActions actions={actions} />
      }
      default: return null
    }
  }

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 'var(--space-4)' }}>
      {/* Toolbar */}
      <div style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-2)' }}>
        <div style={{ width: 130, flexShrink: 0 }}>
          <Select value={hwTypeFilter} onChange={(e) => setHwTypeFilter(e.target.value)} placeholder="All Types">
            <option value="">All Types</option>
            {BOARD_TYPES.map((bt) => <option key={bt.value} value={bt.value}>{bt.label}</option>)}
          </Select>
        </div>
        <div style={{ width: 140, flexShrink: 0 }}>
          <Select value={channelFilter} onChange={(e) => setChannelFilter(e.target.value)} placeholder="All Channels">
            <option value="">All Channels</option>
            {CHANNELS.map((c) => <option key={c} value={c}>{c}</option>)}
          </Select>
        </div>
        <div style={{ flex: 1, minWidth: 0, maxWidth: 320 }}>
          <SearchBar value={search} onChange={setSearch} placeholder="Search firmware…" />
        </div>
        <div style={{ marginLeft: 'auto' }} />
        {canAdd && (
          <Button variant="primary" onClick={() => setShowUpload(true)}>
            + Upload
          </Button>
        )}
      </div>

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

      <DataTable
        columns={columns}
        data={filteredFirmware}
        loading={loading}
        keyField="id"
        emptyMessage="No firmware versions found."
        sortKey={sortKey}
        sortDir={sortDir}
        onSort={(key, dir) => { setSortKey(key); setSortDir(dir) }}
        allColumns={ALL_COLUMNS.filter((c) => c.key !== '__actions')}
        visibleKeys={visibleKeys}
        onColumnChange={handleColChange}
      />

      {/* Modals */}
      <ChangelogModal fw={changelogFw} onClose={() => setChangelogFw(null)} />

      {(showUpload || editTarget) && (
        <FirmwareFormModal
          initial={editTarget ?? null}
          onClose={() => { setShowUpload(false); setEditTarget(null) }}
          onSaved={async () => { setShowUpload(false); setEditTarget(null); await fetchFirmware() }}
        />
      )}

      <ConfirmDialog
        open={!!deleteTarget}
        variant="danger"
        title="Delete Firmware Release?"
        message={deleteTarget ? `Delete ${BOARD_TYPE_LABELS[deleteTarget.hw_type] || deleteTarget.hw_type} v${deleteTarget.version} (${deleteTarget.channel})? This cannot be undone.` : ''}
        confirmLabel="Delete"
        loading={deleting}
        onConfirm={handleDelete}
        onCancel={() => setDeleteTarget(null)}
      />
    </div>
  )
}
