import React, { Fragment, useCallback, useEffect, useState } from 'react'
import { GripVertical, Pencil } from 'lucide-react'
import {
  defaultSection,
  exerciseRow,
  noteRow,
  sectionPlannedMinutes,
} from '../utils/trainingUnitSectionsForm'
import { PLANNING_MODULE_UX_MODE } from '../config/planningModuleUx'

const DND_TU_ITEM = 'application/x-shinkan-training-unit-item'
const DND_TU_SECTION = 'application/x-shinkan-training-section-v1'

/** Optische Trennlinie: wird als normale Zwischen-Anmerkung gespeichert (Inhalt nur dieser Marker). */
const SECTION_INSERT_SEPARATOR_BODY = '---'

function normalizedPlanningModuleChainId(raw) {
  if (raw == null || raw === '') return null
  const n = typeof raw === 'number' ? raw : Number(raw)
  return Number.isFinite(n) && n >= 1 ? n : null
}

function dtHasType(e, mime) {
  const t = e?.dataTransfer?.types
  if (!t || !mime) return false
  if (typeof t.contains === 'function' && t.contains(mime)) return true
  return Array.from(t).includes(mime)
}

function truncatePreview(text, max = 160) {
  const t = (text || '').replace(/\s+/g, ' ').trim()
  if (t.length <= max) return t
  return `${t.slice(0, max - 1)}…`
}

/** Liest den zusammenhängenden Lauf eines Moduls im Abschnitt (ab erstem Item mit dieser Herkunfts-ID). */
function gatherPlanningModuleOutline(items, startIdx, moduleId) {
  const exercises = []
  let notes = 0
  for (let j = startIdx; j < (items?.length ?? 0); j++) {
    const row = items[j]
    if (normalizedPlanningModuleChainId(row.source_training_module_id) !== moduleId) break
    if (row.item_type === 'note') {
      const bod = (row.note_body || '').trim()
      if (bod === SECTION_INSERT_SEPARATOR_BODY) continue
      notes += 1
      continue
    }
    const t =
      (row.exercise_title || '').trim() ||
      (row.exercise_id ? `Übung #${row.exercise_id}` : 'Übung')
    exercises.push(t)
  }
  return { exercises, notes }
}

const MODULE_OUTLINE_PREVIEW_MAX = 8

const PLANNING_USE_COMPACT_LEGEND = PLANNING_MODULE_UX_MODE === 'compact_tag_legend'

/** Stabile Farbzurodnung aus Modul-ID (nur Darstellung). */
function planningModulePalette(moduleId) {
  const id = normalizedPlanningModuleChainId(moduleId)
  const n = id != null && id >= 1 ? Math.floor(Number(id)) : 1
  const golden = ((n >>> 0) * 2654435761 + n * 73856093) >>> 0
  const h = golden % 360
  const border = `hsl(${h} 52% 36%)`
  const soft = `hsl(${h} 42% 94%)`
  return { border, soft, hue: h }
}

function PlanningModuleRowTag({ moduleId, title }) {
  const p = planningModulePalette(moduleId)
  const lbl = truncatePreview(title || `Modul #${moduleId}`, 34).trim()
  const fullTitle = ((title || '').trim() || `Modul #${moduleId}`).trim()
  return (
    <span
      className="tu-planning-mod-tag"
      style={{ borderColor: p.border, backgroundColor: p.soft }}
      title={`${fullTitle} (Bibliotheks-ID ${moduleId})`}
    >
      <span className="tu-planning-mod-tag__dot" style={{ background: p.border }} aria-hidden />
      <span className="tu-planning-mod-tag__text">Aus Modul: {lbl}</span>
    </span>
  )
}

/** Eindeutige Module im Abschnitt mit Zählerständen für die Legende. */
function sectionModuleLegendModel(items) {
  const map = new Map()
  for (const row of items || []) {
    const id = normalizedPlanningModuleChainId(row.source_training_module_id)
    if (id == null) continue
    if (!map.has(id)) {
      map.set(id, {
        id,
        title: (((row.source_module_title || '').trim() || '') || `Modul #${id}`).trim(),
        exercises: 0,
        notes: 0,
      })
    }
    const agg = map.get(id)
    if ((row.item_type || '') === 'note') {
      const bod = ((row.note_body || '').trim() || '').trim()
      if (bod === SECTION_INSERT_SEPARATOR_BODY) continue
      agg.notes += 1
    } else {
      agg.exercises += 1
    }
  }
  return [...map.values()].sort((a, b) => a.id - b.id)
}

function renderModulePlanningHead(modBandTitle, modOutline, showModuleBand) {
  if (!showModuleBand || !modOutline) return null
  return (
    <div className="tu-module-bundle-head" role="group" aria-label={`Modul ${modBandTitle}`}>
      <div className="tu-module-bundle-head__stripe" aria-hidden />
      <div className="tu-module-bundle-head__main">
        <span className="tu-module-bundle-head__kicker">Aus Modul</span>
        <strong className="tu-module-bundle-head__title">{modBandTitle}</strong>
        {modOutline.exercises.length === 0 && modOutline.notes === 0 ? (
          <p className="tu-module-bundle-head__empty">Ohne strukturierten Inhalt angezeigt.</p>
        ) : (
          <ol className="tu-module-bundle-head__list" start={1}>
            {modOutline.exercises.slice(0, MODULE_OUTLINE_PREVIEW_MAX).map((tx, ox) => (
              <li key={`mo-li-${modBandTitle}-${ox}`}>{tx}</li>
            ))}
          </ol>
        )}
        {modOutline.exercises.length > MODULE_OUTLINE_PREVIEW_MAX ? (
          <p className="tu-module-bundle-head__more">
            … und noch {modOutline.exercises.length - MODULE_OUTLINE_PREVIEW_MAX}{' '}
            {modOutline.exercises.length - MODULE_OUTLINE_PREVIEW_MAX === 1 ? 'Übung' : 'Übungen'}
          </p>
        ) : null}
        {modOutline.notes > 0 ? (
          <p className="tu-module-bundle-head__meta">
            sowie {modOutline.notes}{' '}
            {modOutline.notes === 1 ? 'Zwischen-Hinweis' : 'Zwischen-Hinweise'}
          </p>
        ) : null}
      </div>
    </div>
  )
}

function reorderBlocksImmutable(blocks, fromI, toBeforeIdx) {
  const b = [...blocks]
  if (fromI < 0 || fromI >= b.length) return blocks
  const [moved] = b.splice(fromI, 1)
  let insertAt = toBeforeIdx
  if (fromI < toBeforeIdx) insertAt = toBeforeIdx - 1
  insertAt = Math.max(0, Math.min(insertAt, b.length))
  b.splice(insertAt, 0, moved)
  return b
}

/**
 * @param {(updater: (prev: Array) => Array) => void} props.onSectionsChange — wie React setState
 * @param {(p: { fromSlot: number, fromSectionIdx: number, toSlot: number, toSectionIdx: number }) => void} [props.onMoveSectionsAcrossSlots] — Rahmenprogramm: Abschnitt zwischen Slots verschieben
 */
export default function TrainingUnitSectionsEditor({
  sections,
  onSectionsChange,
  onRequestExercisePick,
  onRequestTrainingModulePick,
  onPeekExercise,
  showExecutionExtras = false,
  heading = 'Abschnitte & Übungen',
  hideHeading = false,
  headingAccessory = null,
  wideExerciseGrid = false,
  enableItemDragReorder = true,
  enableSectionDragReorder = true,
  slotIndex = null,
  onMoveSectionsAcrossSlots = null,
  /** Dünnes „+“ zwischen Einträge: Popup für Typ (Übung, Modul, …) */
  betweenInsertMenus = true,
}) {
  const ensure = (prev) =>
    prev && prev.length ? prev : [defaultSection()]

  const patch = useCallback(
    (updater) => {
      onSectionsChange((prev) => updater(ensure(prev)))
    },
    [onSectionsChange]
  )

  const sectionToSlot =
    slotIndex !== null && slotIndex !== undefined ? Number(slotIndex) : -1

  const updateSectionField = (sIdx, field, val) => {
    patch((prev) =>
      prev.map((s, i) => (i === sIdx ? { ...s, [field]: val } : s))
    )
  }

  const addSection = () => {
    patch((prev) => [...prev, defaultSection(`Abschnitt ${prev.length + 1}`)])
  }

  const removeSection = (sIdx) => {
    patch((prev) => {
      const next = prev.filter((_, i) => i !== sIdx)
      return next.length ? next : [defaultSection()]
    })
  }

  const moveSection = (sIdx, dir) => {
    patch((prev) => {
      const p = [...prev]
      const ta = sIdx + dir
      if (ta < 0 || ta >= p.length) return p
      ;[p[sIdx], p[ta]] = [p[ta], p[sIdx]]
      return p
    })
  }

  const insertItemAt = useCallback(
    (sIdx, beforeIx, row) => {
      patch((prev) =>
        prev.map((s, i) => {
          if (i !== sIdx) return s
          const items = [...(s.items || [])]
          const ix = Math.max(
            0,
            Math.min(Number(beforeIx) || 0, items.length)
          )
          items.splice(ix, 0, row)
          return { ...s, items }
        })
      )
    },
    [patch]
  )

  const addItem = (sIdx, kind) => {
    patch((prev) =>
      prev.map((s, i) => {
        if (i !== sIdx) return s
        const items = [...(s.items || [])]
        items.push(kind === 'note' ? noteRow() : exerciseRow())
        return { ...s, items }
      })
    )
  }

  const removeItem = (sIdx, iIdx) => {
    patch((prev) =>
      prev.map((s, si) =>
        si !== sIdx ? s : { ...s, items: (s.items || []).filter((_, ii) => ii !== iIdx) }
      )
    )
  }

  const moveItem = (sIdx, iIdx, dir) => {
    patch((prev) =>
      prev.map((s, si) => {
        if (si !== sIdx) return s
        const items = [...(s.items || [])]
        const ta = iIdx + dir
        if (ta < 0 || ta >= items.length) return s
        ;[items[iIdx], items[ta]] = [items[ta], items[iIdx]]
        return { ...s, items }
      })
    )
  }

  const updateItem = (sIdx, iIdx, field, val) => {
    patch((prev) =>
      prev.map((s, si) =>
        si !== sIdx
          ? s
          : {
              ...s,
              items: (s.items || []).map((row, ii) =>
                ii === iIdx ? { ...row, [field]: val } : row
              ),
            }
      )
    )
  }

  const [textEdit, setTextEdit] = useState(null)
  /** { sIdx: number, beforeIx: number } – Einfüge-Popup („+“ zwischen Zeilen) */
  const [insertChooser, setInsertChooser] = useState(null)
  const [draggingPos, setDraggingPos] = useState(null)
  const [dropTargetPos, setDropTargetPos] = useState(null)

  const [dropSectionBand, setDropSectionBand] = useState(null)
  /** { slot: number, beforeIdx: number } */

  useEffect(() => {
    if (!textEdit) return
    const onKey = (e) => {
      if (e.key === 'Escape') setTextEdit(null)
    }
    window.addEventListener('keydown', onKey)
    return () => window.removeEventListener('keydown', onKey)
  }, [textEdit])

  useEffect(() => {
    if (!insertChooser) return
    const onKey = (e) => {
      if (e.key === 'Escape') setInsertChooser(null)
    }
    window.addEventListener('keydown', onKey)
    return () => window.removeEventListener('keydown', onKey)
  }, [insertChooser])

  const closeInsertChooser = useCallback(() => setInsertChooser(null), [])

  const insertSlotKeyPrefix =
    slotIndex !== null && slotIndex !== undefined ? `sl${slotIndex}-` : ''

  const clearSectionDnD = () => setDropSectionBand(null)

  const onSectionDragStart = (e, sIdx) => {
    if (!enableSectionDragReorder) return
    e.stopPropagation()
    try {
      e.dataTransfer.effectAllowed = 'move'
      e.dataTransfer.setData(
        DND_TU_SECTION,
        JSON.stringify({
          fromSlot: sectionToSlot,
          fromSectionIdx: sIdx,
        })
      )
    } catch {
      /* ignore */
    }
    setDropSectionBand(null)
  }

  const onSectionBandDragOver = (e, beforeIdx) => {
    if (!enableSectionDragReorder) return
    if (!dtHasType(e, DND_TU_SECTION)) return
    e.preventDefault()
    e.stopPropagation()
    try {
      e.dataTransfer.dropEffect = 'move'
    } catch {
      /* ignore */
    }
    setDropSectionBand({ slot: sectionToSlot, beforeIdx })
  }

  const onSectionBandDrop = (e, insertBeforeIdx) => {
    if (!enableSectionDragReorder) return
    e.preventDefault()
    e.stopPropagation()
    clearSectionDnD()
    let raw = ''
    try {
      raw = e.dataTransfer.getData(DND_TU_SECTION)
    } catch {
      return
    }
    if (!raw) return
    let data
    try {
      data = JSON.parse(raw)
    } catch {
      return
    }
    const fromSi = data.fromSectionIdx
    const fromSlot = typeof data.fromSlot === 'number' ? data.fromSlot : -1
    if (typeof fromSi !== 'number') return

    if (
      typeof onMoveSectionsAcrossSlots === 'function' &&
      sectionToSlot >= 0 &&
      fromSlot >= 0
    ) {
      onMoveSectionsAcrossSlots({
        fromSlot,
        fromSectionIdx: fromSi,
        toSlot: sectionToSlot,
        toSectionIdx: insertBeforeIdx,
      })
      return
    }

    patch((prev) => reorderBlocksImmutable(prev, fromSi, insertBeforeIdx))
  }

  const onItemDragStart = (e, sIdx, iIdx) => {
    if (!enableItemDragReorder) return
    e.stopPropagation()
    try {
      e.dataTransfer.effectAllowed = 'move'
      e.dataTransfer.setData(
        DND_TU_ITEM,
        JSON.stringify({ sectionIndex: sIdx, itemIndex: iIdx })
      )
    } catch {
      /* ignore */
    }
    setDraggingPos({ sIdx, iIdx })
  }

  const clearDragChrome = () => {
    setDraggingPos(null)
    setDropTargetPos(null)
  }

  const onItemDragOverRow = (e, sIdx, iIdx) => {
    if (!enableItemDragReorder) return
    if (!dtHasType(e, DND_TU_ITEM)) return
    e.preventDefault()
    e.stopPropagation()
    try {
      e.dataTransfer.dropEffect = 'move'
    } catch {
      /* ignore */
    }
    setDropTargetPos({ sIdx, iIdx })
  }

  const onItemDropRow = (e, toSIdx, toIdx) => {
    if (!enableItemDragReorder) return
    e.preventDefault()
    e.stopPropagation()
    let raw = ''
    try {
      raw = e.dataTransfer.getData(DND_TU_ITEM)
    } catch {
      clearDragChrome()
      return
    }
    if (!raw) {
      clearDragChrome()
      return
    }
    let data
    try {
      data = JSON.parse(raw)
    } catch {
      clearDragChrome()
      return
    }
    const fromS = data.sectionIndex
    const fromI = data.itemIndex
    if (typeof fromS !== 'number' || typeof fromI !== 'number') {
      clearDragChrome()
      return
    }
    if (fromS === toSIdx && fromI === toIdx) {
      clearDragChrome()
      return
    }

    patch((prev) => {
      const list = ensure(prev)
      if (
        fromS < 0 ||
        fromS >= list.length ||
        toSIdx < 0 ||
        toSIdx >= list.length ||
        typeof toIdx !== 'number'
      ) {
        return prev
      }

      const fromItems = [...(list[fromS].items || [])]
      if (fromI < 0 || fromI >= fromItems.length) return prev

      const moved = fromItems[fromI]
      fromItems.splice(fromI, 1)

      if (fromS === toSIdx) {
        let insertAt = toIdx
        if (fromI < toIdx) insertAt = toIdx - 1
        const bounded = Math.max(0, Math.min(insertAt, fromItems.length))
        fromItems.splice(bounded, 0, moved)
        return list.map((sec, i) => (i === fromS ? { ...sec, items: fromItems } : sec))
      }

      const toItems = [...(list[toSIdx].items || [])]
      const insertAt = Math.max(0, Math.min(toIdx, toItems.length))
      toItems.splice(insertAt, 0, moved)
      return list.map((sec, i) => {
        if (i === fromS) return { ...sec, items: fromItems }
        if (i === toSIdx) return { ...sec, items: toItems }
        return sec
      })
    })
    clearDragChrome()
  }

  const applyTextEdit = () => {
    if (!textEdit) return
    const { kind, sIdx, iIdx, draft } = textEdit
    if (kind === 'zwischen-note') {
      updateItem(sIdx, iIdx, 'note_body', draft)
    } else if (kind === 'exercise-notes') {
      updateItem(sIdx, iIdx, 'notes', draft)
    }
    setTextEdit(null)
  }

  const renderBetweenInsertBand = (sIdx, beforeIx, itemCount) => {
    const posLabel =
      beforeIx === 0
        ? 'vor dem ersten Eintrag'
        : beforeIx >= itemCount
          ? 'am Ende des Abschnitts'
          : `vor Eintrag ${beforeIx + 1}`
    return (
      <div className="tu-insert-slot">
        <button
          type="button"
          className="tu-insert-slot__btn"
          aria-haspopup="dialog"
          aria-label={`Inhalt einfügen (${posLabel})`}
          title={`Hier einfügen (${posLabel})`}
          onClick={() => setInsertChooser({ sIdx, beforeIx })}
        >
          +
        </button>
      </div>
    )
  }

  const list = ensure(sections)

  return (
    <div
      className={
        'training-unit-sections-editor' +
        (wideExerciseGrid ? ' training-unit-sections-editor--wide' : '')
      }
    >
      {(!hideHeading || headingAccessory) ? (
        <div
          className="tu-editor-heading-toolbar"
          style={{
            display: 'flex',
            flexWrap: 'wrap',
            justifyContent: 'space-between',
            alignItems: 'center',
            gap: '10px',
            marginBottom: '0.75rem',
          }}
        >
          {!hideHeading ? (
            <h3 style={{ margin: 0, fontSize: '1rem', flex: '1 1 200px', minWidth: 0 }}>
              {heading}
            </h3>
          ) : headingAccessory ? (
            <span style={{ flex: '1 1 auto', minWidth: 0 }} />
          ) : null}
          {headingAccessory ? (
            <div
              style={{
                display: 'flex',
                flexWrap: 'wrap',
                gap: '8px',
                justifyContent: 'flex-end',
                alignItems: 'center',
              }}
            >
              {headingAccessory}
            </div>
          ) : null}
        </div>
      ) : null}
      {list.map((sec, sIdx) => {
        const planMin = sectionPlannedMinutes(sec)
        const itemCount = sec.items?.length ?? 0
        const moduleLegend = PLANNING_USE_COMPACT_LEGEND ? sectionModuleLegendModel(sec.items) : []
        const bandActiveBefore = (bx) =>
          enableSectionDragReorder &&
          dropSectionBand &&
          dropSectionBand.slot === sectionToSlot &&
          dropSectionBand.beforeIdx === bx

        return (
          <Fragment key={`secFrag-${sIdx}`}>
            {enableSectionDragReorder ? (
              <div
                className={'tu-section-dropband' + (bandActiveBefore(sIdx) ? ' tu-section-dropband--active' : '')}
                title="Abschnitt hier einfügen"
                onDragOver={(e) => {
                  if (!enableSectionDragReorder) return
                  if (!dtHasType(e, DND_TU_SECTION)) return
                  onSectionBandDragOver(e, sIdx)
                }}
                onDragLeave={(e) => {
                  if (e.currentTarget.contains(e.relatedTarget)) return
                  clearSectionDnD()
                }}
                onDrop={(e) => onSectionBandDrop(e, sIdx)}
              />
            ) : null}
            <div
              className="tu-section-shell"
              style={{
                marginBottom: '1rem',
                padding: '0.75rem',
                background: 'var(--surface2)',
                borderRadius: '10px',
                border: '1px solid var(--border, rgba(0,0,0,0.08))',
              }}
            >
              <div
                style={{
                  display: 'flex',
                  flexWrap: 'wrap',
                  gap: '0.5rem',
                  marginBottom: '0.5rem',
                  alignItems: 'flex-start',
                }}
              >
                {enableSectionDragReorder ? (
                  <span
                    className="tu-sec-drag-grip"
                    draggable
                    onDragStart={(e) => onSectionDragStart(e, sIdx)}
                    role="button"
                    tabIndex={0}
                    aria-label="Abschnitt ziehen"
                    title="Abschnitt ziehen"
                  >
                    <GripVertical size={16} strokeWidth={2} aria-hidden />
                  </span>
                ) : null}
                <input
                  className="form-input"
                  style={{ flex: '2 1 180px', marginBottom: 0 }}
                  value={sec.title}
                  onChange={(e) => updateSectionField(sIdx, 'title', e.target.value)}
                  placeholder="Abschnittstitel (z. B. Aufwärmen)"
                />
                <div style={{ display: 'flex', gap: '4px', alignSelf: 'center' }}>
                  <button
                    type="button"
                    aria-label="Abschnitt hoch"
                    onClick={() => moveSection(sIdx, -1)}
                    disabled={sIdx === 0}
                    style={{ padding: '4px 10px', opacity: sIdx === 0 ? 0.35 : 1 }}
                  >
                    ▲
                  </button>
                  <button
                    type="button"
                    aria-label="Abschnitt runter"
                    onClick={() => moveSection(sIdx, 1)}
                    disabled={sIdx === list.length - 1}
                    style={{
                      padding: '4px 10px',
                      opacity: sIdx === list.length - 1 ? 0.35 : 1,
                    }}
                  >
                    ▼
                  </button>
                </div>
                <button
                  type="button"
                  className="btn btn-secondary framework-ctrl framework-ctrl--xs"
                  onClick={() => removeSection(sIdx)}
                >
                  Abschnitt entfernen
                </button>
              </div>
              <textarea
                className="form-input"
                rows={2}
                value={sec.guidance_notes}
                onChange={(e) =>
                  updateSectionField(sIdx, 'guidance_notes', e.target.value)
                }
                placeholder="Hinweise zum Abschnitt (Material, Zeit, Zielrichtung …)"
              />
              {planMin > 0 && (
                <p style={{ fontSize: '0.78rem', color: 'var(--text2)', marginTop: '0.35rem' }}>
                  Geplant in diesem Abschnitt: ca. {planMin} Min. (Übungen)
                </p>
              )}

              {betweenInsertMenus ? renderBetweenInsertBand(sIdx, 0, itemCount) : null}

              {(sec.items || []).map((it, iIdx) => {
                const dropHere =
                  enableItemDragReorder &&
                  dropTargetPos?.sIdx === sIdx &&
                  dropTargetPos?.iIdx === iIdx
                const dragHere =
                  enableItemDragReorder &&
                  draggingPos?.sIdx === sIdx &&
                  draggingPos?.iIdx === iIdx
                const rowCommon =
                  'tu-item-row' +
                  (dropHere ? ' tu-item-row--drop-target' : '') +
                  (dragHere ? ' tu-item-row--dragging' : '')

                const dndRowProps = enableItemDragReorder
                  ? {
                      onDragOverCapture: (ev) => onItemDragOverRow(ev, sIdx, iIdx),
                      onDrop: (ev) => onItemDropRow(ev, sIdx, iIdx),
                    }
                  : {}

                const prevIt = iIdx > 0 ? sec.items[iIdx - 1] : null
                const curMn = normalizedPlanningModuleChainId(it.source_training_module_id)
                const showModuleBand =
                  curMn != null && curMn !== normalizedPlanningModuleChainId(prevIt?.source_training_module_id)
                const modBandTitle =
                  (it.source_module_title || '').trim() ||
                  (curMn != null ? `Modul #${curMn}` : '')

                const modOutline =
                  !PLANNING_USE_COMPACT_LEGEND &&
                  showModuleBand &&
                  curMn != null
                    ? gatherPlanningModuleOutline(sec.items, iIdx, curMn)
                    : null
                const fromModClass =
                  curMn != null
                    ? PLANNING_USE_COMPACT_LEGEND
                      ? ' tu-item-row--from-module-soft'
                      : ' tu-item-row--from-module'
                    : ''
                const modBorderVarStyle =
                  PLANNING_USE_COMPACT_LEGEND && curMn != null
                    ? { '--tu-mod-border': planningModulePalette(curMn).border }
                    : undefined

                if (it.item_type === 'note') {
                  const isSepLine = (it.note_body || '').trim() === SECTION_INSERT_SEPARATOR_BODY
                  const notePv = truncatePreview(it.note_body || '', 260)
                  const noteHasText = Boolean((it.note_body || '').trim()) && !isSepLine
                  return (
                    <Fragment key={`${insertSlotKeyPrefix}sec-${sIdx}-blk-${iIdx}`}>
                      {!PLANNING_USE_COMPACT_LEGEND &&
                        renderModulePlanningHead(modBandTitle, modOutline, showModuleBand)}
                      <div
                        className={
                          `${rowCommon} tu-item-row--note` +
                          (isSepLine ? ' tu-item-row--separator-note' : '') +
                          fromModClass
                        }
                        {...dndRowProps}
                        style={modBorderVarStyle}
                      >
                      {enableItemDragReorder ? (
                        <span
                          className="tu-row-grip"
                          draggable
                          onDragStart={(e) => onItemDragStart(e, sIdx, iIdx)}
                          onDragEnd={clearDragChrome}
                          role="button"
                          tabIndex={0}
                          aria-label="Eintrag ziehen"
                        >
                          <GripVertical size={15} strokeWidth={2} aria-hidden />
                        </span>
                      ) : null}
                      <div className="tu-item-row__nudge">
                        <button
                          type="button"
                          aria-label="Eintrag nach oben"
                          onClick={() => moveItem(sIdx, iIdx, -1)}
                          disabled={iIdx === 0}
                        >
                          ▲
                        </button>
                        <button
                          type="button"
                          aria-label="Eintrag nach unten"
                          onClick={() => moveItem(sIdx, iIdx, 1)}
                          disabled={iIdx === sec.items.length - 1}
                        >
                          ▼
                        </button>
                      </div>
                      <div className="tu-item-row__body tu-item-row__body--note">
                        {!isSepLine && PLANNING_USE_COMPACT_LEGEND && curMn ? (
                          <PlanningModuleRowTag moduleId={curMn} title={modBandTitle} />
                        ) : null}
                        <span className="tu-item-row__meta-label">
                          {isSepLine ? 'Trennung' : 'Zwischen-Anmerkung'}
                        </span>
                        {isSepLine ? (
                          <div
                            className="tu-item-row__separator-line"
                            role="separator"
                            aria-label="Trennlinie im Ablauf"
                          />
                        ) : (
                          <p
                            className={`tu-item-row__preview tu-item-row__preview--clamp${noteHasText ? '' : ' tu-item-row__preview--empty'}`}
                            title={noteHasText ? (it.note_body || '').trim() : undefined}
                          >
                            {noteHasText ? notePv : '—'}
                          </p>
                        )}
                      </div>
                      <button
                        type="button"
                        className="tu-icon-btn"
                        title={isSepLine ? 'Trennung bearbeiten' : 'Zwischen-Anmerkung bearbeiten'}
                        aria-label={isSepLine ? 'Trennung bearbeiten' : 'Zwischen-Anmerkung bearbeiten'}
                        onClick={() =>
                          setTextEdit({
                            kind: 'zwischen-note',
                            sIdx,
                            iIdx,
                            draft: it.note_body || '',
                          })
                        }
                      >
                        <Pencil size={15} strokeWidth={2} aria-hidden />
                      </button>
                      <button
                        type="button"
                        className="tu-item-row__remove"
                        title="Entfernen"
                        aria-label={isSepLine ? 'Trennung entfernen' : 'Zwischen-Anmerkung entfernen'}
                        onClick={() => removeItem(sIdx, iIdx)}
                      >
                        ✗
                      </button>
                    </div>
                    {betweenInsertMenus ? renderBetweenInsertBand(sIdx, iIdx + 1, itemCount) : null}
                    </Fragment>
                  )
                }

                const variantOpts = Array.isArray(it.variants) ? it.variants : []
                const exTitle =
                  it.exercise_title || (it.exercise_id ? `Übung #${it.exercise_id}` : '')
                const annotPrev = truncatePreview(it.notes || '', 220)
                const annotHasText = Boolean((it.notes || '').trim())
                const hasVariants = variantOpts.length > 0 && it.exercise_id
                const variantIdPeek =
                  it.exercise_variant_id === '' || it.exercise_variant_id == null
                    ? undefined
                    : Number(it.exercise_variant_id)

                return (
                  <Fragment key={`${insertSlotKeyPrefix}sec-${sIdx}-blk-${iIdx}`}>
                    {!PLANNING_USE_COMPACT_LEGEND &&
                      renderModulePlanningHead(modBandTitle, modOutline, showModuleBand)}
                    <div
                      className={`${rowCommon} tu-item-row--exercise${fromModClass}`}
                      {...dndRowProps}
                      style={modBorderVarStyle}
                    >
                    <div className="tu-item-row__mainline">
                      {enableItemDragReorder ? (
                        <span
                          className="tu-row-grip"
                          draggable
                          onDragStart={(e) => onItemDragStart(e, sIdx, iIdx)}
                          onDragEnd={clearDragChrome}
                          role="button"
                          tabIndex={0}
                          aria-label="Eintrag ziehen"
                        >
                          <GripVertical size={15} strokeWidth={2} aria-hidden />
                        </span>
                      ) : null}
                      <div className="tu-item-row__nudge">
                        <button
                          type="button"
                          aria-label="Eintrag nach oben"
                          onClick={() => moveItem(sIdx, iIdx, -1)}
                          disabled={iIdx === 0}
                        >
                          ▲
                        </button>
                        <button
                          type="button"
                          aria-label="Eintrag nach unten"
                          onClick={() => moveItem(sIdx, iIdx, 1)}
                          disabled={iIdx === sec.items.length - 1}
                        >
                          ▼
                        </button>
                      </div>
                      <div className="tu-item-row__body tu-item-row__body--exercise">
                        <div className="tu-ex-title-line">
                          {exTitle ? (
                            <strong className="tu-ex-title">{exTitle}</strong>
                          ) : (
                            <span className="tu-ex-title-placeholder">Keine Übung gewählt</span>
                          )}
                          {PLANNING_USE_COMPACT_LEGEND && curMn ? (
                            <PlanningModuleRowTag moduleId={curMn} title={modBandTitle} />
                          ) : null}
                          <span className="tu-ex-inline-actions">
                            <button
                              type="button"
                              className="btn btn-secondary framework-ctrl framework-ctrl--xs"
                              onClick={() =>
                                onRequestExercisePick?.({
                                  sectionIndex: sIdx,
                                  itemIndex: iIdx,
                                })
                              }
                            >
                              {exTitle ? 'Wechseln' : 'Übung suchen…'}
                            </button>
                            {it.exercise_id && onPeekExercise ? (
                              <button
                                type="button"
                                className="btn btn-secondary framework-ctrl framework-ctrl--xs"
                                onClick={() =>
                                  onPeekExercise(Number(it.exercise_id), variantIdPeek)
                                }
                              >
                                Vorschau
                              </button>
                            ) : null}
                          </span>
                        </div>
                        <div className="tu-ex-meta-line">
                          {hasVariants ? (
                            <select
                              className={`form-input tu-ex-variant-select${
                                wideExerciseGrid ? ' tu-ex-variant-select--wide' : ''
                              }`}
                              value={
                                it.exercise_variant_id === '' ||
                                it.exercise_variant_id == null
                                  ? ''
                                  : String(it.exercise_variant_id)
                              }
                              onChange={(e) => {
                                const raw = e.target.value
                                updateItem(
                                  sIdx,
                                  iIdx,
                                  'exercise_variant_id',
                                  raw === '' ? '' : parseInt(raw, 10)
                                )
                              }}
                              title="Übungsvariante"
                            >
                              <option value="">Stammübung</option>
                              {variantOpts.map((v) => (
                                <option key={v.id} value={v.id}>
                                  {v.variant_name || `Variante #${v.id}`}
                                </option>
                              ))}
                            </select>
                          ) : null}
                          <div className="tu-ex-annot">
                            <span
                              className={`tu-item-row__preview tu-ex-annot__text${annotHasText ? '' : ' tu-item-row__preview--empty'}`}
                              title={annotHasText ? (it.notes || '').trim() : undefined}
                            >
                              {annotHasText ? annotPrev : '—'}
                            </span>
                            <button
                              type="button"
                              className="tu-icon-btn"
                              title="Anmerkung zur Übung"
                              aria-label="Anmerkung zur Übung bearbeiten"
                              onClick={() =>
                                setTextEdit({
                                  kind: 'exercise-notes',
                                  sIdx,
                                  iIdx,
                                  draft: it.notes || '',
                                })
                              }
                            >
                              <Pencil size={15} strokeWidth={2} aria-hidden />
                            </button>
                          </div>
                        </div>
                      </div>
                      <div className="tu-item-row__side">
                        <input
                          type="number"
                          className="form-input tu-ex-duration"
                          min={1}
                          value={it.planned_duration_min}
                          onChange={(e) =>
                            updateItem(sIdx, iIdx, 'planned_duration_min', e.target.value)
                          }
                          placeholder="Min"
                          title="Geplante Dauer (Minuten)"
                        />
                        <button
                          type="button"
                          className="tu-item-row__remove"
                          title="Übung entfernen"
                          aria-label="Übung entfernen"
                          onClick={() => removeItem(sIdx, iIdx)}
                        >
                          ✗
                        </button>
                      </div>
                    </div>

                    {showExecutionExtras ? (
                      <div className="tu-ex-debrief">
                        <div className="tu-ex-debrief__grow">
                          <span className="tu-item-row__meta-label">Abweichungen beim Durchführen</span>
                          <textarea
                            className="form-input tu-ex-debrief__textarea"
                            rows={3}
                            value={it.modifications || ''}
                            onChange={(e) =>
                              updateItem(sIdx, iIdx, 'modifications', e.target.value)
                            }
                            placeholder="Was lief anders? Anpassungen für spätere Planung…"
                          />
                        </div>
                        <div className="tu-ex-debrief__ist">
                          <span className="tu-item-row__meta-label">Ist (Min)</span>
                          <input
                            type="number"
                            className="form-input tu-ex-duration"
                            min={1}
                            value={it.actual_duration_min}
                            onChange={(e) =>
                              updateItem(sIdx, iIdx, 'actual_duration_min', e.target.value)
                            }
                            placeholder="IST"
                            title="Tatsächliche Dauer (Minuten); dieselbe Spaltenbreite wie „Min“ (Plan) oben"
                          />
                        </div>
                      </div>
                    ) : null}
                  </div>
                  {betweenInsertMenus ? renderBetweenInsertBand(sIdx, iIdx + 1, itemCount) : null}
                  </Fragment>
                )
              })}

              {enableItemDragReorder ? (
                <div
                  className={`tu-item-append-drop${
                    dropTargetPos?.sIdx === sIdx && dropTargetPos?.iIdx === itemCount
                      ? ' tu-item-append-drop--active'
                      : ''
                  }`}
                  title="Hierhin ziehen, um nach unten einzufügen"
                  onDragOverCapture={(e) => onItemDragOverRow(e, sIdx, itemCount)}
                  onDrop={(e) => onItemDropRow(e, sIdx, itemCount)}
                />
              ) : null}

              <div style={{ marginTop: '0.65rem' }}>
                {betweenInsertMenus ? (
                  <p style={{ margin: 0, fontSize: '0.8rem', color: 'var(--text3)', lineHeight: 1.45, maxWidth: '42rem' }}>
                    Über die +-Zeilen zwischen den Einträgen fügst du an der gewünschten Stelle Inhalte ein. Reihenfolge
                    weiter per Ziehen oder den Pfeiltasten ändern.
                  </p>
                ) : (
                  <div style={{ display: 'flex', flexWrap: 'wrap', gap: '6px' }}>
                    <button
                      type="button"
                      className="btn btn-secondary framework-ctrl framework-ctrl--xs"
                      onClick={() => onRequestExercisePick?.({ sectionIndex: sIdx })}
                    >
                      + Übung
                    </button>
                    <button
                      type="button"
                      className="btn btn-secondary framework-ctrl framework-ctrl--xs"
                      onClick={() => addItem(sIdx, 'note')}
                    >
                      + Anmerkung
                    </button>
                  </div>
                )}
              </div>

              {moduleLegend.length ? (
                <div
                  className="tu-section-mod-legend"
                  aria-label="Liste der eingebundenen Trainingsmodule in diesem Abschnitt"
                >
                  <div className="tu-section-mod-legend__caption">Übernommene Module im Abschnitt</div>
                  <ul className="tu-section-mod-legend__list">
                    {moduleLegend.map((e) => {
                      const pal = planningModulePalette(e.id)
                      return (
                        <li key={`mod-leg-${sIdx}-${e.id}`} className="tu-section-mod-legend__item">
                          <span
                            className="tu-section-mod-legend__swatch"
                            style={{ background: pal.border }}
                            title={`Farbe wie an den Zeilen (Modul #${e.id})`}
                            aria-hidden
                          />
                          <span className="tu-section-mod-legend__text">
                            <span className="tu-section-mod-legend__title">
                              {(e.title || '').trim() || `Modul #${e.id}`}
                            </span>
                            <span className="tu-section-mod-legend__meta">
                              ID {e.id} · {e.exercises}{' '}
                              {e.exercises === 1 ? 'Übung' : 'Übungen'}
                              {e.notes > 0 ? (
                                <>
                                  {' '}
                                  · {e.notes} {e.notes === 1 ? 'Zwischen-Hinweis' : 'Zwischen-Hinweise'}
                                </>
                              ) : null}
                            </span>
                          </span>
                        </li>
                      )
                    })}
                  </ul>
                </div>
              ) : null}
            </div>
          </Fragment>
        )
      })}

      {enableSectionDragReorder ? (
        <div
          className={
            'tu-section-dropband tu-section-dropband--end' +
            (dropSectionBand &&
            dropSectionBand.slot === sectionToSlot &&
            dropSectionBand.beforeIdx === list.length
              ? ' tu-section-dropband--active'
              : '')
          }
          title="Abschnitt am Ende einfügen"
          onDragOver={(e) => {
            if (!dtHasType(e, DND_TU_SECTION)) return
            onSectionBandDragOver(e, list.length)
          }}
          onDragLeave={(e) => {
            if (e.currentTarget.contains(e.relatedTarget)) return
            clearSectionDnD()
          }}
          onDrop={(e) => onSectionBandDrop(e, list.length)}
        />
      ) : null}

      <button
        type="button"
        className="btn btn-secondary framework-ctrl framework-ctrl--xs"
        onClick={addSection}
      >
        + Abschnitt hinzufügen
      </button>

      {insertChooser ? (
        <div
          className="tu-textedit-backdrop"
          role="presentation"
          onMouseDown={(e) => {
            if (e.target === e.currentTarget) closeInsertChooser()
          }}
        >
          <div
            className="tu-textedit-panel"
            role="dialog"
            aria-modal="true"
            aria-labelledby="tu-insert-chooser-title"
            onMouseDown={(e) => e.stopPropagation()}
          >
            <h4 id="tu-insert-chooser-title" className="tu-textedit-title">
              An dieser Stelle einfügen
            </h4>
            <p style={{ margin: '0 0 0.75rem', fontSize: '0.86rem', color: 'var(--text2)', lineHeight: 1.45 }}>
              Die neue Zeile erscheint genau hier; Reihenfolge kannst du wie gewohnt per Ziehen oder Pfeilen
              ändern.
            </p>
            <div className="tu-insert-chooser-actions">
              <button
                type="button"
                className="btn btn-primary tu-insert-chooser-actions__full"
                onClick={() => {
                  const { sIdx, beforeIx } = insertChooser
                  closeInsertChooser()
                  onRequestExercisePick?.({
                    sectionIndex: sIdx,
                    insertBeforeIndex: beforeIx,
                  })
                }}
              >
                Übung auswählen …
              </button>
              {onRequestTrainingModulePick ? (
                <button
                  type="button"
                  className="btn btn-secondary tu-insert-chooser-actions__full"
                  onClick={() => {
                    const ctx = { ...insertChooser }
                    closeInsertChooser()
                    onRequestTrainingModulePick({
                      sectionIndex: ctx.sIdx,
                      insertBeforeIndex: ctx.beforeIx,
                    })
                  }}
                >
                  Trainingsmodul …
                </button>
              ) : null}
              <button
                type="button"
                className="btn btn-secondary tu-insert-chooser-actions__full"
                onClick={() => {
                  const { sIdx, beforeIx } = insertChooser
                  insertItemAt(sIdx, beforeIx, noteRow())
                  closeInsertChooser()
                }}
              >
                Zwischen-Anmerkung
              </button>
              <button
                type="button"
                className="btn btn-secondary tu-insert-chooser-actions__full"
                onClick={() => {
                  const { sIdx, beforeIx } = insertChooser
                  const r = noteRow()
                  r.note_body = SECTION_INSERT_SEPARATOR_BODY
                  insertItemAt(sIdx, beforeIx, r)
                  closeInsertChooser()
                }}
              >
                Trennlinie
              </button>
              <button type="button" className="btn btn-secondary tu-insert-chooser-actions__full" onClick={closeInsertChooser}>
                Abbrechen
              </button>
            </div>
          </div>
        </div>
      ) : null}

      {textEdit ? (
        <div
          className="tu-textedit-backdrop"
          role="presentation"
          onMouseDown={(e) => {
            if (e.target === e.currentTarget) setTextEdit(null)
          }}
        >
          <div
            className="tu-textedit-panel"
            role="dialog"
            aria-modal="true"
            aria-labelledby="tu-textedit-title"
            onMouseDown={(e) => e.stopPropagation()}
          >
            <h4 id="tu-textedit-title" className="tu-textedit-title">
              {textEdit.kind === 'zwischen-note'
                ? 'Zwischen-Anmerkung'
                : 'Anmerkung zur Übung'}
            </h4>
            <textarea
              className="form-input tu-textedit-textarea"
              rows={5}
              value={textEdit.draft}
              onChange={(e) =>
                setTextEdit((prev) => (prev ? { ...prev, draft: e.target.value } : prev))
              }
              placeholder={
                textEdit.kind === 'zwischen-note'
                  ? 'Hinweise zwischen Übungen …'
                  : 'Kurze Anmerkung zur Übung'
              }
            />
            <div className="tu-textedit-actions">
              <button type="button" className="btn btn-primary" onClick={applyTextEdit}>
                Übernehmen
              </button>
              <button
                type="button"
                className="btn btn-secondary"
                onClick={() => setTextEdit(null)}
              >
                Abbrechen
              </button>
            </div>
          </div>
        </div>
      ) : null}
    </div>
  )
}
