import { useState, useRef, useMemo, useEffect } from 'react'
import Icon from './Icon'
import ConfirmDeleteEbene from './ConfirmDeleteEbene'
import ContextMenu from './ContextMenu'
import { BarCombo, BarButton } from './BarControls'
import { setLayerStyle, deleteEbene, moveSelectionToEbene, openEbenenSettings } from '../lib/rhinoBridge'

const MODES = [
  { value: 'all_force',   label: 'Alle anzeigen' },
  { value: 'all',         label: 'Ausgewählte' },
  { value: 'active',      label: 'Nur aktive' },
  { value: 'grey',        label: 'Andere grau' },
  { value: 'grey_locked', label: 'Andere grau & gesperrt' },
]

const LW_PRESETS = [0.02, 0.10, 0.13, 0.18, 0.25, 0.35, 0.50, 0.70, 1.00]

function ColorPicker({ color, onChange }) {
  const ref = useRef(null)
  return (
    <>
      <div
        onClick={(ev) => { ev.stopPropagation(); ref.current?.click() }}
        title="Farbe ändern"
        style={{
          width: 12, height: 12, borderRadius: 2,
          background: color, flexShrink: 0,
          border: '1px solid var(--border)',
          cursor: 'pointer',
        }}
      />
      <input
        ref={ref}
        type="color"
        value={color}
        onChange={(ev) => onChange(ev.target.value)}
        onClick={(ev) => ev.stopPropagation()}
        style={{ position: 'absolute', opacity: 0, width: 0, height: 0, pointerEvents: 'none' }}
      />
    </>
  )
}

function LwCell({ lw, onChange }) {
  const [editing, setEditing] = useState(false)
  const [value,   setValue]   = useState(lw.toFixed(2))

  const commit = () => {
    const v = parseFloat(value)
    if (!isNaN(v) && v > 0) onChange(v)
    else setValue(lw.toFixed(2))
    setEditing(false)
  }

  const step = (dir) => {
    let next
    if (dir > 0) next = LW_PRESETS.find(p => p > lw + 0.001)
    else         next = [...LW_PRESETS].reverse().find(p => p < lw - 0.001)
    if (next !== undefined) onChange(next)
  }

  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 2, width: 42, justifyContent: 'flex-end', flexShrink: 0 }}>
      {editing ? (
        <input
          type="number" step="0.01" min="0.01" max="2.0"
          value={value}
          autoFocus
          onChange={(ev) => setValue(ev.target.value)}
          onBlur={commit}
          onKeyDown={(ev) => { if (ev.key === 'Enter') commit(); if (ev.key === 'Escape') { setValue(lw.toFixed(2)); setEditing(false) } }}
          onClick={(ev) => ev.stopPropagation()}
          style={{ width: 28, fontSize: 9, padding: '1px 2px', textAlign: 'right' }}
        />
      ) : (
        <span
          onDoubleClick={(ev) => { ev.stopPropagation(); setEditing(true); setValue(lw.toFixed(2)) }}
          title="Doppelklick zum Bearbeiten"
          style={{ fontSize: 9, fontFamily: 'var(--font-mono)', color: 'var(--text-muted)', cursor: 'text', minWidth: 22, textAlign: 'right' }}
        >{lw.toFixed(2)}</span>
      )}
      <div style={{ display: 'flex', flexDirection: 'column', gap: 0 }}>
        <button className="btn-step" onClick={(ev) => { ev.stopPropagation(); step(+1) }} style={{ width: 10, height: 6 }}>
          <Icon name="arrow_drop_up" size={9} />
        </button>
        <button className="btn-step" onClick={(ev) => { ev.stopPropagation(); step(-1) }} style={{ width: 10, height: 6 }}>
          <Icon name="arrow_drop_down" size={9} />
        </button>
      </div>
    </div>
  )
}

function EditableText({ value, onCommit, style, fontWeight, fontSize, autoEditTrigger }) {
  const [editing, setEditing] = useState(false)
  const [val,     setVal]     = useState(value)
  const lastTrigger = useRef(null)
  const inputRef    = useRef(null)

  // External trigger -> Edit-Modus aktivieren
  useEffect(() => {
    if (autoEditTrigger && autoEditTrigger !== lastTrigger.current) {
      lastTrigger.current = autoEditTrigger
      setVal(value)
      setEditing(true)
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [autoEditTrigger])

  // Beim Edit-Start: Inhalt selektieren
  useEffect(() => {
    if (editing && inputRef.current) {
      inputRef.current.focus()
      try { inputRef.current.select() } catch (e) {}
    }
  }, [editing])

  const commit = () => {
    const trimmed = (val ?? '').trim()
    if (trimmed && trimmed !== value) onCommit(trimmed)
    else setVal(value)
    setEditing(false)
  }

  if (editing) {
    return (
      <input
        ref={inputRef}
        value={val}
        onChange={(ev) => setVal(ev.target.value)}
        onBlur={commit}
        onKeyDown={(ev) => {
          if (ev.key === 'Enter') commit()
          if (ev.key === 'Escape') { setVal(value); setEditing(false) }
        }}
        onClick={(ev) => ev.stopPropagation()}
        style={{ ...style, fontWeight, fontSize, padding: '1px 4px' }}
      />
    )
  }
  return (
    <span
      onDoubleClick={(ev) => { ev.stopPropagation(); setVal(value); setEditing(true) }}
      title="Doppelklick zum Umbenennen"
      style={{ ...style, fontWeight, fontSize, cursor: 'text' }}
    >{value}</span>
  )
}

// --- Tree-Helper -----------------------------------------------------------
// Rekursive Updates: code ist global eindeutig (Children duerfen keinen
// bestehenden Top-Level Code haben). Helper finden/aendern den passenden
// Eintrag irgendwo im Tree.
function _updateInTree(ebenen, code, patch) {
  return ebenen.map(e => {
    if (e.code === code) return { ...e, ...patch }
    if (Array.isArray(e.children) && e.children.length) {
      return { ...e, children: _updateInTree(e.children, code, patch) }
    }
    return e
  })
}

function _removeFromTree(ebenen, code) {
  const out = []
  for (const e of ebenen) {
    if (e.code === code) continue
    if (Array.isArray(e.children) && e.children.length) {
      out.push({ ...e, children: _removeFromTree(e.children, code) })
    } else {
      out.push(e)
    }
  }
  return out
}

function _addChildInTree(ebenen, parentCode, child) {
  return ebenen.map(e => {
    if (e.code === parentCode) {
      const kids = Array.isArray(e.children) ? e.children : []
      return { ...e, children: [...kids, child] }
    }
    if (Array.isArray(e.children) && e.children.length) {
      return { ...e, children: _addChildInTree(e.children, parentCode, child) }
    }
    return e
  })
}

function _findInTree(ebenen, code) {
  for (const e of ebenen) {
    if (e.code === code) return e
    if (Array.isArray(e.children) && e.children.length) {
      const f = _findInTree(e.children, code)
      if (f) return f
    }
  }
  return null
}

function _allCodes(ebenen) {
  const out = []
  for (const e of ebenen) {
    out.push(e.code)
    if (Array.isArray(e.children) && e.children.length) {
      out.push(..._allCodes(e.children))
    }
  }
  return out
}

function EbeneRow({ e, depth, hasChildren, expanded, onToggleExpand, active, mode, onClick, onContextMenu, onToggleVisible, onToggleLock, onColorChange, onLwChange, onNameChange, onCodeChange, onDelete, autoEditCode, autoEditName, rowRef }) {
  // Auge-Logik analog GeschossManager: immer rendern, nur dimmen wenn Mode
  // das Eye-Flag ueberschreibt (active / all_force). Klick auf Auge in
  // diesen Modi wechselt zu "Ausgewählte" damit die Aktion wirkt.
  let eyeIcon, eyeOn, eyeOpacity, eyeTitle
  if (active) {
    eyeIcon    = e.visible !== false ? 'visibility' : 'visibility_off'
    eyeOn      = true
    eyeOpacity = 1
    eyeTitle   = e.visible !== false
      ? 'Normalerweise sichtbar (aktive Ebene wird trotzdem gezeigt)'
      : 'Normalerweise ausgeblendet — wird nur sichtbar weil aktiv'
  } else if (mode === 'all_force') {
    eyeIcon    = 'visibility'
    eyeOn      = true
    eyeOpacity = 0.35
    eyeTitle   = 'Im „Alle anzeigen"-Mode immer sichtbar — Klick wechselt in „Ausgewählte"'
  } else if (mode === 'active') {
    eyeIcon    = e.visible !== false ? 'visibility' : 'visibility_off'
    eyeOn      = false
    eyeOpacity = 0.35
    eyeTitle   = 'Im „Nur aktive"-Mode ausgeblendet — Klick wechselt in „Ausgewählte"'
  } else {
    eyeIcon    = e.visible !== false ? 'visibility' : 'visibility_off'
    eyeOn      = e.visible !== false
    eyeOpacity = 1
    eyeTitle   = e.visible !== false ? 'Ausblenden' : 'Einblenden'
  }
  return (
    <div
      ref={rowRef}
      data-ebene-code={e.code}
      onClick={onClick}
      onContextMenu={onContextMenu}
      style={{
        display: 'flex', alignItems: 'center', gap: 4,
        padding: '1px 12px',
        paddingLeft: 12 + (depth || 0) * 12,
        margin: 0,
        background: active ? 'var(--active-dim)'
                  : (e.visible !== false) ? 'var(--bg-item)'
                  : 'var(--bg-panel)',
        // Eckige Tabellen-Zeile mit Accent-Strip links fuer aktive Ebene
        borderRadius: 0,
        borderLeft: '3px solid ' + (active ? 'var(--accent)' : 'transparent'),
        borderBottom: '1px solid var(--border-light)',
        opacity: (!active && e.visible === false && mode !== 'all') ? 0.45 : 1,
        cursor: 'pointer',
        userSelect: 'none',
        minHeight: 24,
      }}
    >
      {hasChildren ? (
        <button
          className="btn-icon-xs"
          onClick={(ev) => { ev.stopPropagation(); onToggleExpand() }}
          title={expanded ? 'Einklappen' : 'Aufklappen'}
          style={{ width: 12, height: 12 }}
        ><Icon name={expanded ? 'expand_more' : 'chevron_right'} size={11} /></button>
      ) : (
        <span style={{ width: 12, flexShrink: 0 }} />
      )}
      <button
        className={`btn-icon-sm ${eyeOn ? 'is-on' : ''}`}
        onClick={(ev) => { ev.stopPropagation(); onToggleVisible() }}
        title={eyeTitle}
        style={{ opacity: eyeOpacity, width: 16, height: 16 }}
      ><Icon name={eyeIcon} size={12} /></button>

      <EditableText
        value={e.code}
        onCommit={onCodeChange}
        autoEditTrigger={autoEditCode}
        fontSize={9}
        style={{ fontFamily: 'var(--font-mono)', color: 'var(--text-muted)', width: 22, textAlign: 'left', flexShrink: 0 }}
      />

      <ColorPicker color={e.color} onChange={onColorChange} />

      <div style={{ flex: 1, minWidth: 0 }}>
        <EditableText
          value={e.name}
          onCommit={onNameChange}
          autoEditTrigger={autoEditName}
          fontWeight={active ? 700 : 400}
          fontSize={11}
          style={{
            color: active ? 'var(--active-light)'
                  : (e.visible !== false) ? 'var(--text-label)'
                  : 'var(--text-muted)',
            display: 'inline-block', width: '100%',
            overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
            lineHeight: 1.2,
          }}
        />
      </div>

      <LwCell lw={e.lw} onChange={onLwChange} />

      <button
        className="btn-icon-xs"
        onClick={(ev) => { ev.stopPropagation(); onToggleLock() }}
        title={e.locked ? 'Entsperren' : 'Sperren'}
        style={{ color: e.locked ? 'var(--warn)' : undefined, width: 14, height: 14 }}
      ><Icon name={e.locked ? 'lock' : 'lock_open'} size={11} /></button>

      <button
        className="btn-icon-xs"
        onClick={(ev) => { ev.stopPropagation(); onDelete() }}
        title="Löschen"
        style={{ width: 14, height: 14 }}
      ><Icon name="close" size={11} /></button>
    </div>
  )
}

function SortHeader({ label, sortKey, sortBy, sortDir, onSort, style }) {
  const active = sortBy === sortKey
  return (
    <span
      className="label-xs"
      onClick={() => onSort(sortKey)}
      style={{
        cursor: 'pointer', userSelect: 'none',
        display: 'inline-flex', alignItems: 'center', gap: 2,
        color: active ? 'var(--text-secondary)' : undefined, ...style,
      }}
    >
      {label}
      {active && <Icon name={sortDir === 'asc' ? 'arrow_upward' : 'arrow_downward'} size={11} />}
    </span>
  )
}

export default function EbenenManager({
  ebenen, activeCode, onActiveChange, onChange, mode, onModeChange, hatchPatterns,
}) {
  const [sortBy,        setSortBy]        = useState('code')
  const [sortDir,       setSortDir]       = useState('asc')
  const [deleteTarget,  setDeleteTarget]  = useState(null)
  const [ctxMenu,       setCtxMenu]       = useState(null)  // { x, y, code }
  const [clipboard,     setClipboard]     = useState(null)  // { color, lw }
  const [autoEdit,      setAutoEdit]      = useState(null)  // { code, field, token }
  const [expanded,      setExpanded]      = useState({})    // { code: true }
  // Settings-Dialog laeuft jetzt in einem echten Rhino-Fenster (Satellite-
  // Window via Eto.Form + WebView). State hier nicht mehr noetig.

  // Bei Auto-Edit: in View scrollen
  useEffect(() => {
    if (!autoEdit) return
    const el = document.querySelector(`[data-ebene-code="${autoEdit.code}"]`)
    if (el && el.scrollIntoView) {
      el.scrollIntoView({ block: 'center', behavior: 'smooth' })
    }
  }, [autoEdit])

  const toggleSort = (key) => {
    if (sortBy === key) setSortDir(d => d === 'asc' ? 'desc' : 'asc')
    else { setSortBy(key); setSortDir('asc') }
  }

  const sortByCurrent = (arr) => {
    const sorted = [...arr]
    sorted.sort((a, b) => {
      let cmp = 0
      if (sortBy === 'code') {
        const ca = parseInt(a.code, 10), cb = parseInt(b.code, 10)
        cmp = (!isNaN(ca) && !isNaN(cb)) ? ca - cb : a.code.localeCompare(b.code)
      } else if (sortBy === 'name') {
        cmp = a.name.localeCompare(b.name)
      } else if (sortBy === 'lw') {
        cmp = a.lw - b.lw
      }
      return sortDir === 'desc' ? -cmp : cmp
    })
    return sorted
  }

  // Sort wirkt innerhalb jeder Ebene des Baums — Children behalten ihre
  // Beziehung zum Parent, werden aber unter sich sortiert.
  const sortedEbenen = useMemo(() => sortByCurrent(ebenen),
    [ebenen, sortBy, sortDir])

  const updateByCode = (code, patch) => {
    onChange(_updateInTree(ebenen, code, patch))
  }

  const handleToggleVisible = (code) => {
    const cur = _findInTree(ebenen, code)
    if (cur) updateByCode(code, { visible: !(cur.visible !== false) })
    // In "active" / "all_force" greift visible-Flag nicht — wer aufs Auge
    // klickt will offensichtlich Sichtbarkeit kontrollieren, also direkt
    // in den "Ausgewählte"-Mode wechseln damit die Aktion wirkt.
    if (mode === 'active' || mode === 'all_force') onModeChange('all')
  }
  const handleToggleLock = (code) => {
    const cur = _findInTree(ebenen, code)
    if (cur) updateByCode(code, { locked: !cur.locked })
  }
  const handleColorChange = (code, color) => {
    updateByCode(code, { color })
    setLayerStyle(code, color, undefined)
  }
  const handleLwChange = (code, lw) => {
    updateByCode(code, { lw })
    setLayerStyle(code, undefined, lw)
  }
  const handleNameChange = (code, name) => {
    updateByCode(code, { name })
    // Wenn wir gerade neue Ebene anlegen (Phase 'name') — fertig
    if (autoEdit && autoEdit.code === code && autoEdit.field === 'name') {
      setAutoEdit(null)
    }
  }
  const handleCodeChange = (oldCode, newCode) => {
    // Code muss global eindeutig sein (sonst gibt es mehrdeutige Layer-Matches)
    if (_allCodes(ebenen).some(c => c === newCode && c !== oldCode)) return
    onChange(_updateInTree(ebenen, oldCode, { code: newCode }))
    // Phase weiterschalten: Code -> Name
    if (autoEdit && autoEdit.code === oldCode && autoEdit.field === 'code') {
      setAutoEdit({ code: newCode, field: 'name', token: Date.now() })
    }
  }
  const handleDelete = (code) => {
    if (ebenen.length <= 1) return
    setDeleteTarget(code)
  }

  const confirmDelete = (moveToCode) => {
    const code = deleteTarget
    deleteEbene(code, moveToCode)
    onChange(_removeFromTree(ebenen, code))
    if (activeCode === code) {
      const flat = ebenen.flatMap(e =>
        [e, ...(Array.isArray(e.children) ? e.children : [])])
      const next = flat.find(e => e.code !== code)
      if (next) onActiveChange(next.code)
    }
    setDeleteTarget(null)
  }

  const nextFreeAfter = (afterCode) => {
    // Naechste freie Nummer NACH afterCode. Codes sind global eindeutig
    // (auch ueber Children) — also alle Codes als Konfliktraum.
    const existing = new Set(_allCodes(ebenen))
    let n = parseInt(afterCode, 10)
    if (isNaN(n)) n = 49
    for (let i = 1; i < 1000; i++) {
      const c = String(n + i).padStart(2, '0')
      if (!existing.has(c)) return c
    }
    const codes = _allCodes(ebenen).map(c => parseInt(c, 10)).filter(x => !isNaN(x))
    return String((codes.length ? Math.max(...codes) : 49) + 1).padStart(2, '0')
  }

  const addNew = () => {
    // KEIN window.prompt — macOS WKWebView blockiert wiederholte
    // JavaScript-Dialoge (erster zeigt, nachfolgende returnen null).
    // Silent-Append mit autoEdit damit der User direkt den Namen
    // eintippen kann.
    const code = nextFreeAfter(activeCode)
    const newEbene = {
      code, name: 'NEU',
      color: '#888888', lw: 0.18, visible: true, locked: false,
    }
    console.log('[EBENEN-UI] addNew →', { activeCode, code, ebenenCountBefore: ebenen.length })
    onChange([...ebenen, newEbene])
    // Code-Feld der neuen Ebene fokussieren — User kann sofort tippen
    // (Tab springt dann zum Name-Feld).
    setAutoEdit({ code, field: 'code', token: Date.now() })
  }

  const duplicateEbene = (code) => {
    const src = _findInTree(ebenen, code)
    if (!src) return
    const dupCode = nextFreeAfter(code)
    const dup = { ...src, code: dupCode, name: src.name + ' KOPIE' }
    // Top-Level Eintrag — wir haengen Duplikat einfach hinten an
    onChange([...ebenen, dup])
  }

  const addChild = (parentCode) => {
    const code = nextFreeAfter(parentCode)
    const child = {
      code, name: 'NEU',
      color: '#888888', lw: 0.18, visible: true, locked: false,
    }
    onChange(_addChildInTree(ebenen, parentCode, child))
    // Parent expanden damit der neue Eintrag sichtbar ist
    setExpanded(s => ({ ...s, [parentCode]: true }))
    setAutoEdit({ code, field: 'code', token: Date.now() })
  }

  const toggleExpand = (code) => {
    setExpanded(s => ({ ...s, [code]: !s[code] }))
  }

  const copyProps = (code) => {
    const e = ebenen.find(x => x.code === code)
    if (e) setClipboard({ color: e.color, lw: e.lw })
  }

  const pasteProps = (code) => {
    if (!clipboard) return
    onChange(ebenen.map(e => e.code === code ? { ...e, ...clipboard } : e))
    setLayerStyle(code, clipboard.color, clipboard.lw)
  }

  const openContextMenu = (ev, code) => {
    ev.preventDefault()
    ev.stopPropagation()
    setCtxMenu({ x: ev.clientX, y: ev.clientY, code })
  }

  const ctxItems = (code) => [
    { label: 'Ebeneneinstellungen…',         icon: 'settings',      onClick: () => {
        const target = _findInTree(ebenen, code)
        if (target) openEbenenSettings(target, hatchPatterns)
      } },
    { divider: true },
    { label: 'Sub-Ebene hinzufügen…',       icon: 'add',           onClick: () => addChild(code) },
    { label: 'Selektion hierher übertragen', icon: 'move_down',     onClick: () => moveSelectionToEbene(code) },
    { divider: true },
    { label: 'Duplizieren',                 icon: 'content_copy',  onClick: () => duplicateEbene(code) },
    { label: 'Eigenschaften kopieren',      icon: 'colorize',      onClick: () => copyProps(code) },
    { label: 'Eigenschaften einfügen',      icon: 'format_paint',  onClick: () => pasteProps(code), disabled: !clipboard },
    { divider: true },
    { label: 'Löschen',                     icon: 'delete',        onClick: () => handleDelete(code), danger: true,
                                                                   disabled: ebenen.length <= 1 },
  ]

  return (
    <>
      <div style={{
        display: 'flex', flexDirection: 'column', gap: 4,
        padding: '6px 14px',
        background: 'var(--bg-section)',
        borderBottom: '1px solid var(--border-light)',
      }}>
        <span className="label-xs">Sichtbarkeit</span>
        <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
          <div style={{ flex: 1, minWidth: 0, display: 'flex' }}>
            <BarCombo
              icon="visibility"
              value={mode}
              onChange={onModeChange}
              title="Sichtbarkeits-Modus"
            >
              {MODES.map(m => <option key={m.value} value={m.value}>{m.label}</option>)}
            </BarCombo>
          </div>
          <BarButton icon="add" onClick={addNew} title="Ebene hinzufügen" />
        </div>
      </div>

      <div style={{
        display: 'flex', alignItems: 'center', gap: 5,
        padding: '2px 14px',
        background: 'var(--bg-section)',
        borderBottom: '1px solid var(--border)',
      }}>
        {/* Master-Eye: alle Ebenen sichtbar/unsichtbar */}
        <button
          className="btn-icon-xs"
          onClick={() => {
            const anyVisible = ebenen.some(e => e.visible !== false)
            // Wenn irgendeine sichtbar -> alle aus. Wenn keine sichtbar -> alle an.
            onChange(ebenen.map(e => ({ ...e, visible: !anyVisible })))
            if (mode === 'active' || mode === 'all_force') onModeChange('all')
          }}
          title={ebenen.every(e => e.visible !== false)
            ? 'Alle Ebenen ausblenden'
            : 'Alle Ebenen einblenden'}
          style={{ width: 18, height: 18,
                    opacity: (mode === 'active' || mode === 'all_force') ? 0.5 : 1 }}
        >
          <Icon
            name={ebenen.every(e => e.visible !== false) ? 'visibility' : 'visibility_off'}
            size={12}
          />
        </button>
        <SortHeader label="Cd" sortKey="code" sortBy={sortBy} sortDir={sortDir} onSort={toggleSort} style={{ width: 24 }} />
        <div style={{ width: 12 }} />
        <SortHeader label="Name" sortKey="name" sortBy={sortBy} sortDir={sortDir} onSort={toggleSort} style={{ flex: 1 }} />
        <SortHeader label="Lw" sortKey="lw" sortBy={sortBy} sortDir={sortDir} onSort={toggleSort} style={{ width: 42, textAlign: 'right', display: 'block' }} />
        {/* Master-Lock: alle Ebenen sperren/entsperren */}
        <button
          className="btn-icon-xs"
          onClick={() => {
            const anyLocked = ebenen.some(e => e.locked === true)
            onChange(ebenen.map(e => ({ ...e, locked: !anyLocked })))
          }}
          title={ebenen.every(e => e.locked === true)
            ? 'Alle Ebenen entsperren'
            : 'Alle Ebenen sperren'}
          style={{ width: 18, height: 18 }}
        >
          <Icon
            name={ebenen.every(e => e.locked === true) ? 'lock' : 'lock_open'}
            size={11}
          />
        </button>
        <div style={{ width: 18 }} />
      </div>

      {(() => {
        // Rekursives Rendern: jede Ebene + sortierte Children (falls expanded)
        const renderRow = (e, depth) => {
          const kids = Array.isArray(e.children) ? e.children : []
          const hasChildren = kids.length > 0
          const isExpanded = !!expanded[e.code]
          const rows = [
            <EbeneRow
              key={e.code}
              e={e}
              depth={depth}
              hasChildren={hasChildren}
              expanded={isExpanded}
              onToggleExpand={() => toggleExpand(e.code)}
              active={e.code === activeCode}
              mode={mode}
              onClick={() => onActiveChange(e.code)}
              onContextMenu={(ev) => openContextMenu(ev, e.code)}
              onToggleVisible={() => handleToggleVisible(e.code)}
              onToggleLock={() => handleToggleLock(e.code)}
              onColorChange={(c) => handleColorChange(e.code, c)}
              onLwChange={(lw) => handleLwChange(e.code, lw)}
              onNameChange={(n) => handleNameChange(e.code, n)}
              onCodeChange={(c) => handleCodeChange(e.code, c)}
              onDelete={() => handleDelete(e.code)}
              autoEditCode={autoEdit && autoEdit.code === e.code && autoEdit.field === 'code' ? autoEdit.token : null}
              autoEditName={autoEdit && autoEdit.code === e.code && autoEdit.field === 'name' ? autoEdit.token : null}
            />
          ]
          if (hasChildren && isExpanded) {
            for (const child of sortByCurrent(kids)) {
              rows.push(...renderRow(child, depth + 1))
            }
          }
          return rows
        }
        return sortedEbenen.flatMap(e => renderRow(e, 0))
      })()}

      {ctxMenu && (
        <ContextMenu
          x={ctxMenu.x} y={ctxMenu.y}
          items={ctxItems(ctxMenu.code)}
          onClose={() => setCtxMenu(null)}
        />
      )}

      {deleteTarget && (
        <ConfirmDeleteEbene
          ebene={ebenen.find(e => e.code === deleteTarget)}
          otherEbenen={ebenen.filter(e => e.code !== deleteTarget)}
          onConfirm={confirmDelete}
          onCancel={() => setDeleteTarget(null)}
        />
      )}

    </>
  )
}
