import React, { useState, useEffect, useCallback, useMemo, useRef } from 'react'
import { Link, useSearchParams } from 'react-router-dom'
import api from '../utils/api'
import { useAuth } from '../context/AuthContext'
import { activeClubMemberships } from '../utils/activeClub'
import ExercisePickerModal from '../components/ExercisePickerModal'
import ExercisePeekModal from '../components/ExercisePeekModal'
import TrainingUnitSectionsEditor from '../components/TrainingUnitSectionsEditor'
import TrainingPlanExerciseVisibilityPanel from '../components/TrainingPlanExerciseVisibilityPanel'
import PageSectionNav from '../components/PageSectionNav'
import {
  defaultSection,
  normalizeUnitToForm,
  enrichSectionsWithVariants,
  buildSectionsPayload,
  hydrateExercisePlanningRow,
  insertTrainingModuleIntoPlanningSections,
} from '../utils/trainingUnitSectionsForm'

/** Kurz-Anzeige Sichtbarkeit (Trainingsmodule, Übungen) */
function trainingVisibilityShortDE(visibility) {
  const v = String(visibility || '').trim().toLowerCase()
  if (v === 'official') return 'Öffentliche Bibliothek'
  if (v === 'club') return 'Verein'
  if (v === 'private') return 'Privat'
  return visibility ? String(visibility) : ''
}

function addDaysIsoDate(isoDay, daysDelta) {
  const d = new Date(`${isoDay}T12:00:00`)
  d.setDate(d.getDate() + daysDelta)
  return d.toISOString().slice(0, 10)
}

function pad2(n) {
  return String(n).padStart(2, '0')
}

function toIsoLocal(d) {
  return `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}`
}

/** Montag = erster Wochentag (ISO-Woche UI) */
function mondayIndex(d) {
  return (d.getDay() + 6) % 7
}

/** Kalendarische Monatsansicht: erster und letzter Tag des sichtbaren Rasters (Mo–So) */
function getCalendarGridRange(ym) {
  const parts = (ym || '').split('-').map(Number)
  const y = parts[0]
  const m = parts[1]
  if (!y || !m || m < 1 || m > 12) {
    const t = new Date()
    return { gridStart: toIsoLocal(t), gridEnd: toIsoLocal(t) }
  }
  const first = new Date(y, m - 1, 1)
  const last = new Date(y, m, 0)
  const gridStart = new Date(first)
  gridStart.setDate(first.getDate() - mondayIndex(first))
  const lastMon = mondayIndex(last)
  const gridEnd = new Date(last)
  gridEnd.setDate(last.getDate() + (6 - lastMon))
  return { gridStart: toIsoLocal(gridStart), gridEnd: toIsoLocal(gridEnd) }
}

function shiftCalendarMonth(ym, delta) {
  const parts = (ym || '').split('-').map(Number)
  const y = parts[0] || new Date().getFullYear()
  const m = parts[1] || 1
  const d = new Date(y, m - 1 + delta, 1)
  return `${d.getFullYear()}-${pad2(d.getMonth() + 1)}`
}

function enumerateIsoDays(fromIso, toIso) {
  const out = []
  const cur = new Date(`${fromIso}T12:00:00`)
  const end = new Date(`${toIso}T12:00:00`)
  while (cur <= end) {
    out.push(toIsoLocal(cur))
    cur.setDate(cur.getDate() + 1)
  }
  return out
}

const WEEKDAYS_DE = ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So']

function toNumList(arr) {
  if (!Array.isArray(arr)) return []
  const out = []
  for (const x of arr) {
    const n = Number(x)
    if (Number.isFinite(n) && n >= 1) out.push(n)
  }
  return out
}

const sessionAssignDefaults = () => ({
  lead_trainer_profile_id: '',
  session_assistants_inherit: true,
  session_assistant_profile_ids: [],
})

/** Co_trainer_ids aus TrainingGroups (Liste/JSON) → Zahlenliste */
function normalizeGroupCoTrainerIds(raw) {
  if (raw == null) return []
  const arr = Array.isArray(raw) ? raw : []
  const out = []
  for (const x of arr) {
    const n = Number(x)
    if (Number.isFinite(n) && n >= 1) out.push(n)
  }
  return out
}

/** Mitgliederverzeichnis-Einträge ohne effektiven Leitungsträger als Co‑Option */
function filterDirectoryExcludingLead(directory, excludeLeadPid) {
  const ex =
    excludeLeadPid != null && excludeLeadPid !== '' && Number.isFinite(Number(excludeLeadPid))
      ? Number(excludeLeadPid)
      : null
  if (ex == null) return directory
  return directory.filter((m) => Number(m.id) !== ex)
}
function TrainingPlanningPage() {
  const { user } = useAuth()
  const [searchParams, setSearchParams] = useSearchParams()
  const unitDeepLinkHandledRef = useRef(null)
  const [groups, setGroups] = useState([])
  const [selectedGroupId, setSelectedGroupId] = useState('')
  const [units, setUnits] = useState([])
  const [planTemplates, setPlanTemplates] = useState([])
  const [loading, setLoading] = useState(true)
  const [showModal, setShowModal] = useState(false)
  const [editingUnit, setEditingUnit] = useState(null)
  /** Abschnitts-Editor bei Bearbeitung: Planung vs. Nachbereitung (Ist & Abweichungen) */
  const [sectionsEditMode, setSectionsEditMode] = useState('planning')
  const [draftPlanTemplateId, setDraftPlanTemplateId] = useState('')
  const [exercisePickerOpen, setExercisePickerOpen] = useState(false)
  const [exercisePickerTarget, setExercisePickerTarget] = useState(null)
  const [planningPeekCtx, setPlanningPeekCtx] = useState(null)

  const today = new Date().toISOString().split('T')[0]
  const thirtyDaysLater = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString().split('T')[0]

  const [frameworkImportOpen, setFrameworkImportOpen] = useState(false)
  const [frameworkProgramsList, setFrameworkProgramsList] = useState([])
  const [fwImportProgramId, setFwImportProgramId] = useState('')
  const [fwImportDetail, setFwImportDetail] = useState(null)
  const [fwImportLoading, setFwImportLoading] = useState(false)
  const [fwImportSelectedSlots, setFwImportSelectedSlots] = useState(() => new Set())
  const [fwImportSlotDates, setFwImportSlotDates] = useState({})
  const [fwImportStartDate, setFwImportStartDate] = useState(today)
  const [fwImportIntervalDays, setFwImportIntervalDays] = useState(7)
  const [fwImportSubmitting, setFwImportSubmitting] = useState(false)

  const [moduleApplyOpen, setModuleApplyOpen] = useState(false)
  const [moduleApplyBusy, setModuleApplyBusy] = useState(false)
  const [moduleApplyList, setModuleApplyList] = useState([])
  const [moduleApplyModuleId, setModuleApplyModuleId] = useState('')
  const [moduleApplySectionIx, setModuleApplySectionIx] = useState(0)
  const [moduleApplyInsertSlot, setModuleApplyInsertSlot] = useState('before:0')
  const [moduleApplyErr, setModuleApplyErr] = useState('')
  const [moduleApplyPlacementLocked, setModuleApplyPlacementLocked] = useState(false)
  const [moduleApplySearchQuery, setModuleApplySearchQuery] = useState('')
  const [modulePickPreview, setModulePickPreview] = useState({
    loading: false,
    moduleId: '',
    exercises: [],
    notes: 0,
    err: '',
  })

  const [startDate, setStartDate] = useState(today)
  const [endDate, setEndDate] = useState(thirtyDaysLater)
  const [planView, setPlanView] = useState('list')
  const [calendarMonthStr, setCalendarMonthStr] = useState(() => today.slice(0, 7))
  const [planScope, setPlanScope] = useState('group')
  const [assignedToMeOnly, setAssignedToMeOnly] = useState(false)
  const [clubDirectory, setClubDirectory] = useState([])
  const [assignModalOpen, setAssignModalOpen] = useState(false)
  const [assignDraft, setAssignDraft] = useState({
    unit: null,
    lead_trainer_profile_id: '',
    session_assistants_inherit: true,
    session_assistant_profile_ids: [],
  })
  const [assignSaving, setAssignSaving] = useState(false)

  const [formData, setFormData] = useState({
    group_id: '',
    planned_date: '',
    planned_time_start: '',
    planned_time_end: '',
    planned_focus: '',
    actual_date: '',
    actual_time_start: '',
    actual_time_end: '',
    attendance_count: '',
    status: 'planned',
    notes: '',
    trainer_notes: '',
    debrief_completed: false,
    sections: [defaultSection()],
    ...sessionAssignDefaults()
  })
  const planningFormRef = useRef(formData)
  planningFormRef.current = formData

  const moduleApplyFilteredList = useMemo(() => {
    const q = moduleApplySearchQuery.trim().toLowerCase().replace(/\s+/g, ' ')
    const words = q ? q.split(' ').filter(Boolean) : []
    const list = Array.isArray(moduleApplyList) ? moduleApplyList : []
    if (!words.length) return list
    return list.filter((m) => {
      const blob = [
        m.title,
        m.summary,
        m.goal,
        m.target_group_notes,
        m.deployment_context_notes,
      ]
        .map((x) => String(x ?? '').toLowerCase())
        .join('\n')
      return words.every((w) => blob.includes(w))
    })
  }, [moduleApplySearchQuery, moduleApplyList])

  const modulePlacementSummary = useMemo(() => {
    const secs = Array.isArray(formData.sections) ? formData.sections : []
    let si =
      typeof moduleApplySectionIx === 'number'
        ? moduleApplySectionIx
        : parseInt(String(moduleApplySectionIx), 10)
    if (!Number.isFinite(si)) si = 0
    si = Math.max(0, Math.min(si, secs.length ? secs.length - 1 : 0))
    const cap = secs[si]?.items?.length ?? 0
    let beforeIx = cap
    if (typeof moduleApplyInsertSlot === 'string' && moduleApplyInsertSlot.startsWith('before:')) {
      const zi = parseInt(moduleApplyInsertSlot.slice('before:'.length), 10)
      if (Number.isFinite(zi)) beforeIx = Math.min(Math.max(0, zi), cap)
    }
    const rawTitle = (secs[si]?.title || '').trim()
    const secTitle = rawTitle || `Abschnitt ${si + 1}`
    let positionDescription
    if (cap <= 0) positionDescription = 'als erste Einträge dieses Abschnitts'
    else if (beforeIx <= 0) positionDescription = 'vor dem ersten Eintrag dieses Abschnitts'
    else if (beforeIx >= cap) positionDescription = 'nach dem letzten Eintrag dieses Abschnitts'
    else positionDescription = `unmittelbar vor Eintrag ${beforeIx + 1} (${cap} Einträge im Abschnitt)`
    return { secTitle, positionDescription }
  }, [formData.sections, moduleApplySectionIx, moduleApplyInsertSlot])

  useEffect(() => {
    if (!moduleApplyOpen || !moduleApplyFilteredList.length) return
    if (moduleApplyFilteredList.some((m) => String(m.id) === String(moduleApplyModuleId))) return
    setModuleApplyModuleId(String(moduleApplyFilteredList[0].id))
  }, [moduleApplyOpen, moduleApplyFilteredList, moduleApplyModuleId])

  const planningModalClubId = useMemo(() => {
    const gid = Number(formData.group_id)
    if (!Number.isFinite(gid) || gid < 1) return null
    const g = groups.find((x) => Number(x.id) === gid)
    if (!g || g.club_id == null || g.club_id === '') return null
    const c = Number(g.club_id)
    return Number.isFinite(c) ? c : null
  }, [groups, formData.group_id])

  const moduleApplyTargetItems = useMemo(() => {
    const secs = formData.sections || []
    if (!secs.length) return []
    let ix =
      typeof moduleApplySectionIx === 'number'
        ? moduleApplySectionIx
        : parseInt(String(moduleApplySectionIx), 10)
    if (!Number.isFinite(ix)) ix = 0
    if (ix < 0 || ix >= secs.length) return []
    const sec = secs[ix]
    return Array.isArray(sec?.items) ? sec.items : []
  }, [formData.sections, moduleApplySectionIx])

  const refreshPlanningSectionMeta = useCallback(async () => {
    const next = await enrichSectionsWithVariants(planningFormRef.current.sections)
    setFormData((prev) => ({ ...prev, sections: next }))
  }, [])

  const loadPlanTemplates = useCallback(async () => {
    try {
      const tpl = await api.listTrainingPlanTemplates()
      setPlanTemplates(tpl)
    } catch (e) {
      console.error('Vorlagen laden:', e)
    }
  }, [])

  const loadData = async () => {
    try {
      const groupsData = await api.listTrainingGroups({ status: 'active' })
      setGroups(groupsData)
      await loadPlanTemplates()

      if (groupsData.length > 0) {
        const ownGroup = groupsData.find((g) => g.trainer_id === user?.id)
        if (ownGroup) {
          setSelectedGroupId(ownGroup.id)
        } else if (groupsData.length === 1) {
          setSelectedGroupId(groupsData[0].id)
        }
      }
    } catch (err) {
      console.error('Failed to load data:', err)
      alert('Fehler beim Laden: ' + err.message)
    } finally {
      setLoading(false)
    }
  }

  const loadUnits = useCallback(async () => {
    if (!selectedGroupId) return
    let start = startDate
    let end = endDate
    if (planView === 'calendar') {
      const r = getCalendarGridRange(calendarMonthStr)
      start = r.gridStart
      end = r.gridEnd
    }
    const gid = parseInt(selectedGroupId, 10)
    const groupRow = groups.find((g) => g.id === gid)
    const clubId = groupRow?.club_id
    try {
      const filters = {
        start_date: start,
        end_date: end
      }
      if (assignedToMeOnly) {
        filters.assigned_to_me = true
      }
      if (planScope === 'club' && clubId) {
        filters.club_id = clubId
      } else {
        filters.group_id = gid
      }
      const unitsData = await api.listTrainingUnits(filters)
      setUnits(unitsData)
    } catch (err) {
      console.error('Failed to load units:', err)
    }
  }, [
    selectedGroupId,
    groups,
    startDate,
    endDate,
    planView,
    calendarMonthStr,
    planScope,
    assignedToMeOnly
  ])

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

  useEffect(() => {
    if (selectedGroupId) {
      loadUnits()
    }
  }, [selectedGroupId, loadUnits])

  const selectedGroupClubIdMemo = useMemo(() => {
    const g = groups.find((gr) => gr.id === parseInt(selectedGroupId, 10))
    return g?.club_id != null ? Number(g.club_id) : null
  }, [groups, selectedGroupId])

  const canClubOrgTraining = useMemo(() => {
    const r = (user?.role || '').toLowerCase()
    if (r === 'admin' || r === 'superadmin') return true
    if (selectedGroupClubIdMemo == null || !Number.isFinite(selectedGroupClubIdMemo)) return false
    const row = activeClubMemberships(user?.clubs).find((c) => Number(c.id) === selectedGroupClubIdMemo)
    return Array.isArray(row?.roles) && row.roles.includes('club_admin')
  }, [user?.role, user?.clubs, selectedGroupClubIdMemo])

  const clubAdminClubIdSet = useMemo(() => {
    const ids = []
    for (const c of activeClubMemberships(user?.clubs)) {
      if (Array.isArray(c.roles) && c.roles.includes('club_admin')) {
        const id = Number(c.id)
        if (Number.isFinite(id)) ids.push(id)
      }
    }
    return new Set(ids)
  }, [user?.clubs])

  useEffect(() => {
    const gid = parseInt(formData.group_id || selectedGroupId || '0', 10)
    const gModal = Number.isFinite(gid) && gid >= 1 ? groups.find((x) => x.id === gid) : null
    const clubForModal = gModal?.club_id != null ? Number(gModal.club_id) : null

    let assignModalClubId = null
    if (assignModalOpen && assignDraft.unit?.group_id != null) {
      const ug = Number(assignDraft.unit.group_id)
      const gAssign = Number.isFinite(ug) ? groups.find((x) => x.id === ug) : null
      if (gAssign?.club_id != null) assignModalClubId = Number(gAssign.club_id)
    }

    const loadClubId =
      showModal && clubForModal != null && Number.isFinite(clubForModal)
        ? clubForModal
        : assignModalOpen && assignModalClubId != null && Number.isFinite(assignModalClubId)
          ? assignModalClubId
          : canClubOrgTraining && selectedGroupClubIdMemo != null && Number.isFinite(selectedGroupClubIdMemo)
            ? selectedGroupClubIdMemo
            : null

    if (loadClubId == null || !Number.isFinite(loadClubId)) {
      setClubDirectory([])
      return undefined
    }
    let cancelled = false
    ;(async () => {
      try {
        const d = await api.clubMembersDirectory(loadClubId)
        if (!cancelled) setClubDirectory(Array.isArray(d) ? d : [])
      } catch (err) {
        if (!cancelled) {
          console.error('Mitgliederverzeichnis:', err)
          setClubDirectory([])
        }
      }
    })()
    return () => {
      cancelled = true
    }
  }, [
    showModal,
    assignModalOpen,
    assignDraft.unit,
    formData.group_id,
    selectedGroupId,
    groups,
    canClubOrgTraining,
    selectedGroupClubIdMemo,
  ])

  useEffect(() => {
    if (!frameworkImportOpen) return
    let cancelled = false
    ;(async () => {
      try {
        const list = await api.listTrainingFrameworkPrograms()
        if (!cancelled) setFrameworkProgramsList(Array.isArray(list) ? list : [])
      } catch (e) {
        if (!cancelled) {
          console.error('Rahmenprogramme laden:', e)
          setFrameworkProgramsList([])
        }
      }
    })()
    return () => {
      cancelled = true
    }
  }, [frameworkImportOpen])

  const openFrameworkImportModal = useCallback(() => {
    setFwImportProgramId('')
    setFwImportDetail(null)
    setFwImportSelectedSlots(new Set())
    setFwImportSlotDates({})
    setFwImportStartDate(new Date().toISOString().split('T')[0])
    setFwImportIntervalDays(7)
    setFrameworkImportOpen(true)
  }, [])

  const onFwImportProgramChange = async (idStr) => {
    setFwImportProgramId(idStr)
    if (!idStr) {
      setFwImportDetail(null)
      return
    }
    setFwImportLoading(true)
    try {
      const d = await api.getTrainingFrameworkProgram(parseInt(idStr, 10))
      setFwImportDetail(d)
      setFwImportSelectedSlots(new Set())
      setFwImportSlotDates({})
    } catch (e) {
      alert(e.message || 'Rahmenprogramm laden fehlgeschlagen')
      setFwImportDetail(null)
    } finally {
      setFwImportLoading(false)
    }
  }

  const toggleFwImportSlot = (slot) => {
    if (!slot?.blueprint_training_unit_id) return
    const sid = slot.id
    setFwImportSelectedSlots((prev) => {
      const n = new Set(prev)
      if (n.has(sid)) n.delete(sid)
      else n.add(sid)
      return n
    })
  }

  const applyFwImportDateSuggestions = () => {
    if (!fwImportDetail?.slots?.length) return
    const sorted = [...fwImportDetail.slots].sort(
      (a, b) => (a.sort_order ?? 0) - (b.sort_order ?? 0)
    )
    let offset = 0
    const iv = Math.max(0, Number(fwImportIntervalDays) || 0)
    const next = {}
    for (const s of sorted) {
      if (!fwImportSelectedSlots.has(s.id)) continue
      if (!s.blueprint_training_unit_id) continue
      next[String(s.id)] = addDaysIsoDate(fwImportStartDate, offset)
      offset += iv
    }
    setFwImportSlotDates((prev) => ({ ...prev, ...next }))
  }

  const submitFrameworkImport = async () => {
    if (!selectedGroupId) {
      alert('Bitte zuerst eine Trainingsgruppe wählen.')
      return
    }
    const gid = parseInt(selectedGroupId, 10)
    if (!fwImportDetail?.slots?.length) return
    const sorted = [...fwImportDetail.slots].sort(
      (a, b) => (a.sort_order ?? 0) - (b.sort_order ?? 0)
    )
    const picks = sorted.filter(
      (s) => fwImportSelectedSlots.has(s.id) && s.blueprint_training_unit_id
    )
    if (!picks.length) {
      alert('Bitte mindestens eine Session mit Ablauf (Blueprint) auswählen.')
      return
    }
    for (const s of picks) {
      const key = String(s.id)
      const date = fwImportSlotDates[key] || fwImportStartDate
      if (!date) {
        alert('Bitte für jede ausgewählte Session ein Datum setzen (oder Datumsvorschläge nutzen).')
        return
      }
    }
    setFwImportSubmitting(true)
    try {
      for (const s of picks) {
        const key = String(s.id)
        const date = fwImportSlotDates[key] || fwImportStartDate
        await api.createTrainingUnitFromFrameworkSlot({
          group_id: gid,
          planned_date: date,
          framework_slot_id: s.id,
        })
      }
      setFrameworkImportOpen(false)
      await loadUnits()
    } catch (e) {
      alert(e.message || 'Übernahme fehlgeschlagen')
    } finally {
      setFwImportSubmitting(false)
    }
  }

  const frameworkLineageText = (unit) => {
    const fpTitle = (unit.origin_framework_program_title || '').trim() || 'Rahmenprogramm'
    const st = (unit.origin_framework_slot_title || '').trim()
    const idx = unit.origin_framework_slot_sort_order
    const slotBit =
      st || (typeof idx === 'number' ? `Session ${idx + 1}` : 'Session')
    return { fpTitle, slotBit, fpId: unit.origin_framework_program_id }
  }

  const handleCreate = () => {
    if (!selectedGroupId) {
      alert('Bitte wähle zuerst eine Trainingsgruppe')
      return
    }
    const group = groups.find((g) => g.id === parseInt(selectedGroupId, 10))
    setEditingUnit(null)
    setDraftPlanTemplateId('')
    setFormData({
      group_id: selectedGroupId,
      planned_date: today,
      planned_time_start: group?.time_start?.slice(0, 5) || '',
      planned_time_end: group?.time_end?.slice(0, 5) || '',
      planned_focus: '',
      actual_date: '',
      actual_time_start: '',
      actual_time_end: '',
      attendance_count: '',
      status: 'planned',
      notes: '',
      trainer_notes: '',
      debrief_completed: false,
      sections: [defaultSection('Hauptteil')],
      ...sessionAssignDefaults()
    })
    setSectionsEditMode('planning')
    setShowModal(true)
  }

  const handleCreateForDate = (isoDay) => {
    if (!selectedGroupId) {
      alert('Bitte wähle zuerst eine Trainingsgruppe')
      return
    }
    const group = groups.find((g) => g.id === parseInt(selectedGroupId, 10))
    setEditingUnit(null)
    setDraftPlanTemplateId('')
    setFormData({
      group_id: selectedGroupId,
      planned_date: isoDay,
      planned_time_start: group?.time_start?.slice(0, 5) || '',
      planned_time_end: group?.time_end?.slice(0, 5) || '',
      planned_focus: '',
      actual_date: '',
      actual_time_start: '',
      actual_time_end: '',
      attendance_count: '',
      status: 'planned',
      notes: '',
      trainer_notes: '',
      debrief_completed: false,
      sections: [defaultSection('Hauptteil')],
      ...sessionAssignDefaults()
    })
    setSectionsEditMode('planning')
    setShowModal(true)
  }

  const applyTemplateFromSelect = async (templateId) => {
    setDraftPlanTemplateId(templateId)
    if (!templateId) return
    try {
      const tpl = await api.getTrainingPlanTemplate(parseInt(templateId, 10))
      setFormData((fd) => ({
        ...fd,
        sections: (tpl.sections || []).length
          ? tpl.sections.map((s) => ({
              title: s.title,
              guidance_notes: s.guidance_text || '',
              items: []
            }))
          : [defaultSection()]
      }))
    } catch (err) {
      alert('Vorlage laden: ' + err.message)
    }
  }

  const handleEdit = useCallback(async (unit) => {
    try {
      const fullUnit = await api.getTrainingUnit(unit.id)
      setEditingUnit(fullUnit)
      setDraftPlanTemplateId(fullUnit.plan_template_id ? String(fullUnit.plan_template_id) : '')
      let sections = normalizeUnitToForm(fullUnit)
      sections = await enrichSectionsWithVariants(sections)
      setFormData({
        group_id: fullUnit.group_id,
        planned_date: fullUnit.planned_date || '',
        planned_time_start: fullUnit.planned_time_start?.slice(0, 5) || '',
        planned_time_end: fullUnit.planned_time_end?.slice(0, 5) || '',
        planned_focus: fullUnit.planned_focus || '',
        actual_date: fullUnit.actual_date || '',
        actual_time_start: fullUnit.actual_time_start?.slice(0, 5) || '',
        actual_time_end: fullUnit.actual_time_end?.slice(0, 5) || '',
        attendance_count: fullUnit.attendance_count ?? '',
        status: fullUnit.status || 'planned',
        notes: fullUnit.notes || '',
        trainer_notes: fullUnit.trainer_notes || '',
        debrief_completed: Boolean(fullUnit.debrief_completed_at),
        sections,
        lead_trainer_profile_id:
          fullUnit.lead_trainer_profile_id != null && fullUnit.lead_trainer_profile_id !== ''
            ? String(fullUnit.lead_trainer_profile_id)
            : '',
        session_assistants_inherit:
          fullUnit.assistant_trainer_profile_ids == null ||
          fullUnit.assistant_trainer_profile_ids === undefined,
        session_assistant_profile_ids: (() => {
          const efLead =
            fullUnit.effective_lead_trainer_profile_id != null
              ? Number(fullUnit.effective_lead_trainer_profile_id)
              : null
          let xs = toNumList(fullUnit.assistant_trainer_profile_ids)
          if (efLead != null && Number.isFinite(efLead)) xs = xs.filter((id) => id !== efLead)
          return xs
        })(),
      })
      setSectionsEditMode(fullUnit.status === 'completed' ? 'debrief' : 'planning')
      setShowModal(true)
    } catch (err) {
      alert('Fehler beim Laden: ' + err.message)
      throw err
    }
  }, [])

  useEffect(() => {
    if (!user?.id || loading) return
    const uid = searchParams.get('unit')
    if (!uid) {
      unitDeepLinkHandledRef.current = null
      return
    }
    if (unitDeepLinkHandledRef.current === uid) return
    const idNum = parseInt(uid, 10)
    if (!Number.isFinite(idNum)) return
    unitDeepLinkHandledRef.current = uid
    handleEdit({ id: idNum })
      .then(() => {
        setSearchParams(
          (prev) => {
            const next = new URLSearchParams(prev)
            next.delete('unit')
            next.delete('debrief')
            return next
          },
          { replace: true }
        )
      })
      .catch(() => {
        unitDeepLinkHandledRef.current = null
        setSearchParams(
          (prev) => {
            const next = new URLSearchParams(prev)
            next.delete('unit')
            next.delete('debrief')
            return next
          },
          { replace: true }
        )
      })
  }, [user?.id, loading, searchParams, handleEdit, setSearchParams])

  const handleSaveAsTemplate = async () => {
    const name = window.prompt('Name für die neue Trainingsvorlage (nur Abschnitts-Gliederung):')
    if (!name?.trim()) return
    try {
      await api.createTrainingPlanTemplate({
        name: name.trim(),
        sections: formData.sections.map((s) => ({
          title: s.title || 'Abschnitt',
          guidance_text: s.guidance_notes?.trim() ? s.guidance_notes.trim() : null
        }))
      })
      await loadPlanTemplates()
      alert('Vorlage gespeichert.')
    } catch (err) {
      alert('Speichern: ' + err.message)
    }
  }

  const openModuleApplyModal = useCallback(async (placement) => {
    setModuleApplyErr('')
    setModuleApplySearchQuery('')
    const placementLocked =
      placement != null &&
      typeof placement.sectionIndex === 'number' &&
      typeof placement.insertBeforeIndex === 'number'
    setModuleApplyPlacementLocked(placementLocked)
    const secs = planningFormRef.current?.sections ?? []
    let secIx = 0
    let before = 0
    if (secs.length) {
      if (placement && typeof placement.sectionIndex === 'number') {
        secIx = Math.min(Math.max(0, placement.sectionIndex), secs.length - 1)
        const items = Array.isArray(secs[secIx]?.items) ? secs[secIx].items : []
        const cap = items.length
        if (typeof placement.insertBeforeIndex === 'number' && Number.isFinite(placement.insertBeforeIndex)) {
          before = Math.min(Math.max(0, placement.insertBeforeIndex), cap)
        } else before = cap
      } else {
        const items = Array.isArray(secs[0]?.items) ? secs[0].items : []
        before = items.length
        secIx = 0
      }
    }
    setModuleApplySectionIx(secIx)
    setModuleApplyInsertSlot(`before:${before}`)
    setModuleApplyOpen(true)
    try {
      const list = await api.listTrainingModules()
      const arr = Array.isArray(list) ? list : []
      setModuleApplyList(arr)
      setModuleApplyModuleId(arr.length ? String(arr[0].id) : '')
    } catch (e) {
      setModuleApplyErr(e.message || 'Module konnten nicht geladen werden')
      setModuleApplyList([])
    }
  }, [])

  const handleApplyTrainingModuleConfirm = useCallback(async () => {
    const mid = parseInt(moduleApplyModuleId, 10)
    if (!Number.isFinite(mid)) {
      alert('Bitte ein Trainingsmodul wählen.')
      return
    }
    let secIx = parseInt(String(moduleApplySectionIx), 10)
    if (!Number.isFinite(secIx)) secIx = 0

    const baseSections = planningFormRef.current?.sections ?? formData.sections ?? []
    if (!baseSections.length) {
      alert('Keine Abschnitte im Formular.')
      return
    }
    if (secIx < 0 || secIx >= baseSections.length) secIx = 0

    const secItems = Array.isArray(baseSections[secIx]?.items) ? baseSections[secIx].items : []
    const itemCap = secItems.length
    let insertBefore = itemCap
    if (typeof moduleApplyInsertSlot === 'string' && moduleApplyInsertSlot.startsWith('before:')) {
      const zi = parseInt(moduleApplyInsertSlot.slice('before:'.length), 10)
      if (Number.isFinite(zi)) insertBefore = Math.min(Math.max(0, zi), itemCap)
    }

    setModuleApplyBusy(true)
    setModuleApplyErr('')
    try {
      const detail = await api.getTrainingModule(mid)
      let nextSections = await insertTrainingModuleIntoPlanningSections({
        sections: baseSections,
        moduleDetail: detail,
        sectionIndex: secIx,
        insertBeforeItemIndex: insertBefore,
      })
      nextSections = await enrichSectionsWithVariants(nextSections)
      setFormData((fd) => ({ ...fd, sections: nextSections }))
      setModuleApplyOpen(false)
      setModuleApplyPlacementLocked(false)
    } catch (e) {
      setModuleApplyErr(e.message || 'Einfügen fehlgeschlagen')
    } finally {
      setModuleApplyBusy(false)
    }
  }, [moduleApplyModuleId, moduleApplySectionIx, moduleApplyInsertSlot])

  useEffect(() => {
    if (!moduleApplyOpen) {
      setModulePickPreview({
        loading: false,
        moduleId: '',
        exercises: [],
        notes: 0,
        err: '',
      })
      return undefined
    }
    const mid = parseInt(String(moduleApplyModuleId), 10)
    if (!Number.isFinite(mid) || mid < 1) {
      setModulePickPreview({
        loading: false,
        moduleId: '',
        exercises: [],
        notes: 0,
        err: '',
      })
      return undefined
    }
    let cancelled = false
    setModulePickPreview({
      loading: true,
      moduleId: String(mid),
      exercises: [],
      notes: 0,
      err: '',
    })
    ;(async () => {
      try {
        const detail = await api.getTrainingModule(mid)
        if (cancelled) return
        const itemsSorted = [...(detail.items ?? [])].sort(
          (a, b) => (a.order_index ?? 0) - (b.order_index ?? 0)
        )
        const uniqueEx = new Set()
        let notes = 0
        for (const row of itemsSorted) {
          if ((row.item_type || '') !== 'note') {
            const eid = row.exercise_id
            if (eid) uniqueEx.add(Number(eid))
            continue
          }
          const b = String(row.note_body ?? '').trim()
          if (b === '---') continue
          notes += 1
        }
        const titleById = new Map()
        await Promise.all(
          [...uniqueEx].map(async (eid) => {
            try {
              const ex = await api.getExercise(eid)
              titleById.set(eid, (ex?.title || '').trim() || `Übung #${eid}`)
            } catch {
              titleById.set(eid, `Übung #${eid}`)
            }
          })
        )
        if (cancelled) return
        const exTitlesInOrder = []
        for (const row of itemsSorted) {
          if ((row.item_type || '') !== 'exercise') continue
          const eid = Number(row.exercise_id)
          if (!Number.isFinite(eid)) continue
          exTitlesInOrder.push(titleById.get(eid) || `Übung #${eid}`)
        }
        setModulePickPreview({
          loading: false,
          moduleId: String(mid),
          exercises: exTitlesInOrder,
          notes,
          err: '',
        })
      } catch (e) {
        if (!cancelled) {
          setModulePickPreview({
            loading: false,
            moduleId: String(mid),
            exercises: [],
            notes: 0,
            err: e?.message || 'Vorschau fehlgeschlagen',
          })
        }
      }
    })()
    return () => {
      cancelled = true
    }
  }, [moduleApplyOpen, moduleApplyModuleId])

  const handleTakeLead = async (unit) => {
    if (!user?.id) return
    try {
      await api.updateTrainingUnit(unit.id, { lead_trainer_profile_id: user.id })
      await loadUnits()
    } catch (err) {
      alert(err.message || 'Leitung konnte nicht übernommen werden')
    }
  }

  const openTrainerAssignModal = (unit) => {
    const effLead =
      unit.effective_lead_trainer_profile_id != null
        ? Number(unit.effective_lead_trainer_profile_id)
        : null
    let coIds = toNumList(unit.assistant_trainer_profile_ids)
    if (effLead != null && Number.isFinite(effLead)) {
      coIds = coIds.filter((id) => id !== effLead)
    }
    setAssignDraft({
      unit,
      lead_trainer_profile_id:
        unit.lead_trainer_profile_id != null && unit.lead_trainer_profile_id !== ''
          ? String(unit.lead_trainer_profile_id)
          : '',
      session_assistants_inherit:
        unit.assistant_trainer_profile_ids == null || unit.assistant_trainer_profile_ids === undefined,
      session_assistant_profile_ids: coIds,
    })
    setAssignModalOpen(true)
  }

  const saveTrainerAssignModal = async () => {
    if (!assignDraft.unit) return
    setAssignSaving(true)
    try {
      const payload = {}
      const leadStr = String(assignDraft.lead_trainer_profile_id || '').trim()
      if (leadStr) payload.lead_trainer_profile_id = parseInt(leadStr, 10)
      else payload.lead_trainer_profile_id = null
      if (assignDraft.session_assistants_inherit) {
        payload.assistant_trainer_profile_ids = null
      } else {
        payload.assistant_trainer_profile_ids = [...assignDraft.session_assistant_profile_ids].sort((a, b) => a - b)
      }
      await api.updateTrainingUnit(assignDraft.unit.id, payload)
      setAssignModalOpen(false)
      setAssignDraft({
        unit: null,
        ...sessionAssignDefaults(),
      })
      await loadUnits()
    } catch (err) {
      alert(err.message || 'Zuweisung konnte nicht gespeichert werden')
    } finally {
      setAssignSaving(false)
    }
  }

  const handleDelete = async (unit) => {
    if (!confirm(`Trainingseinheit vom ${unit.planned_date} wirklich löschen?`)) return
    try {
      await api.deleteTrainingUnit(unit.id)
      await loadUnits()
    } catch (err) {
      alert('Fehler beim Löschen: ' + err.message)
    }
  }

  const handleSubmit = async (e) => {
    e.preventDefault()
    if (!formData.group_id || !formData.planned_date) {
      alert('Gruppe und Datum sind Pflichtfelder')
      return
    }
    try {
      const sectionsPayload = buildSectionsPayload(formData.sections)
      const payload = {
        planned_date: formData.planned_date,
        planned_time_start: formData.planned_time_start || null,
        planned_time_end: formData.planned_time_end || null,
        planned_focus: formData.planned_focus || null,
        actual_date: formData.actual_date || null,
        actual_time_start: formData.actual_time_start || null,
        actual_time_end: formData.actual_time_end || null,
        attendance_count: formData.attendance_count ? parseInt(formData.attendance_count, 10) : null,
        status: formData.status || 'planned',
        notes: formData.notes || null,
        trainer_notes: formData.trainer_notes || null,
        sections: sectionsPayload
      }
      if (editingUnit) {
        payload.debrief_completed =
          (formData.status || '') === 'completed' ? !!formData.debrief_completed : false
      }
      const leadStr = String(formData.lead_trainer_profile_id || '').trim()
      if (leadStr) {
        payload.lead_trainer_profile_id = parseInt(leadStr, 10)
      } else if (editingUnit) {
        payload.lead_trainer_profile_id = null
      }
      if (formData.session_assistants_inherit) {
        if (editingUnit) payload.assistant_trainer_profile_ids = null
      } else {
        payload.assistant_trainer_profile_ids = [...formData.session_assistant_profile_ids].sort(
          (a, b) => a - b
        )
      }
      if (!editingUnit) {
        payload.group_id = parseInt(formData.group_id, 10)
        if (draftPlanTemplateId) {
          payload.plan_template_id = parseInt(draftPlanTemplateId, 10)
        }
      }

      if (editingUnit) {
        await api.updateTrainingUnit(editingUnit.id, payload)
      } else {
        await api.createTrainingUnit(payload)
      }
      setShowModal(false)
      await loadUnits()
    } catch (err) {
      alert('Fehler beim Speichern: ' + err.message)
    }
  }

  const updateFormField = (field, value) => {
    setFormData((prev) => {
      if (field !== 'lead_trainer_profile_id') {
        const patch = { ...prev, [field]: value }
        if (field === 'status' && value !== 'completed') {
          patch.debrief_completed = false
        }
        return patch
      }
      const ts = typeof value === 'string' ? value.trim() : String(value ?? '').trim()
      const strip = new Set()
      if (ts !== '') {
        const nid = parseInt(ts, 10)
        if (Number.isFinite(nid)) strip.add(nid)
      } else {
        const gidParsed = parseInt(prev.group_id || selectedGroupId || '0', 10)
        const gr =
          Number.isFinite(gidParsed) && gidParsed >= 1
            ? groups.find((xg) => xg.id === gidParsed)
            : null
        if (gr?.trainer_id != null) {
          const ht = Number(gr.trainer_id)
          if (Number.isFinite(ht)) strip.add(ht)
        }
      }
      const assistants = prev.session_assistant_profile_ids.filter((id) => !strip.has(id))
      return { ...prev, lead_trainer_profile_id: value, session_assistant_profile_ids: assistants }
    })
  }

  const calendarGridDays = useMemo(() => {
    const r = getCalendarGridRange(calendarMonthStr)
    return enumerateIsoDays(r.gridStart, r.gridEnd)
  }, [calendarMonthStr])

  const unitsByPlannedDate = useMemo(() => {
    const m = new Map()
    for (const u of units) {
      const raw = u.planned_date
      if (!raw) continue
      const key = String(raw).slice(0, 10)
      if (!m.has(key)) m.set(key, [])
      m.get(key).push(u)
    }
    return m
  }, [units])

  const calendarMonthTitle = useMemo(() => {
    const p = calendarMonthStr.split('-').map(Number)
    const y = p[0]
    const mo = p[1]
    if (!y || !mo) return ''
    return new Date(y, mo - 1, 1).toLocaleDateString('de-DE', { month: 'long', year: 'numeric' })
  }, [calendarMonthStr])

  const mayConfigureSessionAssignments = useCallback(
    (unit) => {
      if (!unit) return false
      const pid = Number(user?.id)
      if (!Number.isFinite(pid)) return false
      const r = (user?.role || '').toLowerCase()
      if (r === 'admin' || r === 'superadmin') return true

      const gClub = unit.group_club_id != null ? Number(unit.group_club_id) : null
      if (Number.isFinite(gClub) && clubAdminClubIdSet.has(gClub)) return true

      const gid = Number(unit.group_id)
      const g = groups.find((gr) => gr.id === gid)
      if (!g) return false

      const cb = unit.created_by != null ? Number(unit.created_by) : NaN
      if (Number.isFinite(cb) && cb === pid) return true

      const ht = g.trainer_id != null ? Number(g.trainer_id) : NaN
      if (Number.isFinite(ht) && ht === pid) return true

      return normalizeGroupCoTrainerIds(g.co_trainer_ids).includes(pid)
    },
    [user?.id, user?.role, groups, clubAdminClubIdSet]
  )

  if (loading) {
    return (
      <div className="app-page" style={{ padding: '2rem 0', textAlign: 'center' }}>
        <div className="spinner"></div>
        <p>Laden...</p>
      </div>
    )
  }

  const selectedGroup = groups.find((g) => g.id === parseInt(selectedGroupId, 10))

  const gidTrainerForm = parseInt(formData.group_id || selectedGroupId || '0', 10)
  const groupForTrainerForm =
    Number.isFinite(gidTrainerForm) && gidTrainerForm >= 1
      ? groups.find((gr) => gr.id === gidTrainerForm)
      : null

  let formTrainerAssignLeadExcludeId = null
  if (groupForTrainerForm?.trainer_id != null) formTrainerAssignLeadExcludeId = Number(groupForTrainerForm.trainer_id)
  const leadDraftTrim = String(formData.lead_trainer_profile_id || '').trim()
  if (leadDraftTrim !== '') {
    const nl = parseInt(leadDraftTrim, 10)
    if (Number.isFinite(nl)) formTrainerAssignLeadExcludeId = nl
  }
  if (editingUnit?.effective_lead_trainer_profile_id != null && leadDraftTrim === '') {
    const el = Number(editingUnit.effective_lead_trainer_profile_id)
    if (Number.isFinite(el)) formTrainerAssignLeadExcludeId = el
  }

  const clubDirectoryForCo = filterDirectoryExcludingLead(clubDirectory, formTrainerAssignLeadExcludeId)

  let assignExcludeLeadPid = null
  if (assignModalOpen && assignDraft.unit) {
    const dl = String(assignDraft.lead_trainer_profile_id || '').trim()
    if (dl !== '') {
      const n = parseInt(dl, 10)
      assignExcludeLeadPid = Number.isFinite(n) ? n : null
    } else if (assignDraft.unit.effective_lead_trainer_profile_id != null) {
      const n = Number(assignDraft.unit.effective_lead_trainer_profile_id)
      assignExcludeLeadPid = Number.isFinite(n) ? n : null
    }
  }
  const clubDirectoryForAssignCo = filterDirectoryExcludingLead(clubDirectory, assignExcludeLeadPid)

  return (
    <div className="app-page">
        <h1 style={{ marginBottom: '0.35rem' }}>Trainingsplanung</h1>

        <div
          style={{
            display: 'flex',
            flexWrap: 'wrap',
            alignItems: 'center',
            gap: '12px',
            marginBottom: '1rem',
          }}
        >
          <span
            className="form-label"
            style={{
              marginBottom: 0,
              fontSize: '0.9rem',
              color: 'var(--text2)',
            }}
          >
            Ansicht
          </span>
          <PageSectionNav
            semantics="toggle"
            ariaLabel="Darstellung Liste oder Kalender"
            value={planView}
            onChange={(id) => {
              if (id === 'calendar') {
                setPlanView('calendar')
                setCalendarMonthStr((prev) => {
                  const fromList = (startDate || '').slice(0, 7)
                  if (/^\d{4}-\d{2}$/.test(fromList)) return fromList
                  return prev || new Date().toISOString().slice(0, 7)
                })
              } else {
                setPlanView('list')
              }
            }}
            items={[
              { id: 'list', label: 'Liste' },
              { id: 'calendar', label: 'Kalender' },
            ]}
            className="page-section-nav--inline planning-ansicht-nav"
          />
          <span style={{ fontSize: '0.8rem', color: 'var(--text3)', lineHeight: 1.35, maxWidth: '22rem' }}>
            {planView === 'list'
              ? 'Zeitraum unten mit Von/Bis filtern.'
              : 'Monat unten wechseln; Termine erscheinen im Raster.'}
          </span>
        </div>

        <p style={{ color: 'var(--text2)', fontSize: '0.95rem', marginBottom: '1.25rem' }}>
          Wähle eine Trainingsgruppe und lege <strong>Trainingseinheiten</strong> für den Zeitraum an (Inhalt: Abschnitte
          und Übungen).
        </p>

        <div className="card" style={{ marginBottom: '1.25rem', padding: '12px 14px' }}>
          <p style={{ margin: '0 0 0.5rem', fontSize: '0.92rem', color: 'var(--text2)' }}>
            Mehrere Einheiten strukturieren auf einmal:{' '}
            <Link to="/planning/framework-programs" style={{ fontWeight: 600, color: 'var(--accent-dark)' }}>
              Trainingsrahmenprogramme
            </Link>{' '}
            (Ziele, Sessions, Vorlagen‑Ablauf).
          </p>
          <p style={{ margin: 0, fontSize: '0.92rem', color: 'var(--text2)' }}>
            Wiederverwendbare Blöcke innerhalb einer Einheit:{' '}
            <Link to="/planning/training-modules" style={{ fontWeight: 600, color: 'var(--accent-dark)' }}>
              Trainingsmodule
            </Link>{' '}
            (übernahme als Kopie beim Bearbeiten einer Einheit).
          </p>
        </div>
        {!loading && groups.length === 0 && (
          <div
            className="card"
            style={{
              marginBottom: '1.25rem',
              borderLeft: '4px solid var(--accent)',
              padding: '1rem 1.25rem'
            }}
          >
            <h2 style={{ fontSize: '1.1rem', marginBottom: '0.5rem' }}>Erst Verein & Gruppe anlegen</h2>
            <p style={{ color: 'var(--text2)', marginBottom: '0.85rem', lineHeight: 1.5 }}>
              Ohne Trainingsgruppe kann hier nichts gebucht werden. Unter <strong>Vereine</strong> legst du einen Verein an
              (kurzer Name genügt), optional eine Sparte, dann eine <strong>Trainingsgruppe</strong>. Wochentage, feste Zeiten oder
              Eigenschaften sind optional und kannst du später ergänzen.
            </p>
            <Link to="/clubs" className="btn btn-primary" style={{ textDecoration: 'none' }}>
              Zu Vereinen & Trainingsgruppen
            </Link>
          </div>
        )}

        <div className="card" style={{ marginBottom: '1.5rem' }}>
          <div
            style={{
              display: 'grid',
              gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))',
              gap: '1rem'
            }}
          >
            <div>
              <label className="form-label">Trainingsgruppe</label>
              <select
                className="form-input"
                value={selectedGroupId}
                onChange={(e) => setSelectedGroupId(e.target.value)}
              >
                <option value="">Bitte wählen</option>
                {groups.map((g) => (
                  <option key={g.id} value={g.id}>
                    {g.name} ({g.club_name})
                  </option>
                ))}
              </select>
            </div>

            {planView === 'list' ? (
              <>
                <div>
                  <label className="form-label">Von</label>
                  <input
                    type="date"
                    className="form-input"
                    value={startDate}
                    onChange={(e) => setStartDate(e.target.value)}
                  />
                </div>

                <div>
                  <label className="form-label">Bis</label>
                  <input
                    type="date"
                    className="form-input"
                    value={endDate}
                    onChange={(e) => setEndDate(e.target.value)}
                  />
                </div>
              </>
            ) : (
              <div
                style={{
                  gridColumn: '1 / -1',
                  display: 'flex',
                  flexWrap: 'wrap',
                  alignItems: 'center',
                  gap: '0.65rem',
                }}
              >
                <button
                  type="button"
                  className="btn btn-secondary framework-ctrl framework-ctrl--xs"
                  aria-label="Voriger Monat"
                  onClick={() => setCalendarMonthStr((prev) => shiftCalendarMonth(prev, -1))}
                >
                  ←
                </button>
                <span
                  style={{
                    fontWeight: 600,
                    fontSize: '1rem',
                    flex: '1 1 auto',
                    textAlign: 'center',
                    minWidth: '12rem',
                  }}
                >
                  {calendarMonthTitle}
                </span>
                <button
                  type="button"
                  className="btn btn-secondary framework-ctrl framework-ctrl--xs"
                  aria-label="Nächster Monat"
                  onClick={() => setCalendarMonthStr((prev) => shiftCalendarMonth(prev, 1))}
                >
                  →
                </button>
                <button
                  type="button"
                  className="btn btn-secondary"
                  style={{ whiteSpace: 'nowrap', padding: '0.35rem 0.65rem', fontSize: '0.85rem' }}
                  onClick={() => setCalendarMonthStr(new Date().toISOString().slice(0, 7))}
                >
                  Aktueller Monat
                </button>
              </div>
            )}

            <div
              style={{
                gridColumn: '1 / -1',
                display: 'flex',
                flexWrap: 'wrap',
                alignItems: 'center',
                gap: '12px',
              }}
            >
              <span className="form-label" style={{ marginBottom: 0, alignSelf: 'center' }}>
                Einblenden
              </span>
              <PageSectionNav
                semantics="toggle"
                ariaLabel="Gruppe oder ganzer Verein"
                value={planScope}
                onChange={setPlanScope}
                items={[
                  { id: 'group', label: 'Nur diese Gruppe', disabled: !selectedGroupId },
                  { id: 'club', label: 'Ganzer Verein', disabled: !selectedGroupId },
                ]}
                className="page-section-nav--inline"
              />
              <label
                style={{
                  display: 'inline-flex',
                  alignItems: 'center',
                  gap: '8px',
                  fontSize: '0.88rem',
                  color: 'var(--text2)',
                  cursor: selectedGroupId ? 'pointer' : 'default',
                  opacity: selectedGroupId ? 1 : 0.65,
                }}
              >
                <input
                  type="checkbox"
                  checked={assignedToMeOnly}
                  disabled={!selectedGroupId}
                  onChange={(e) => setAssignedToMeOnly(e.target.checked)}
                />
                Nur meine Zuordnung (Leitung / Co)
              </label>
              <p
                style={{
                  fontSize: '0.78rem',
                  color: 'var(--text3)',
                  lineHeight: 1.45,
                  flex: '1 1 220px',
                  margin: 0,
                }}
              >
                Neue Termine gelten immer für die gewählte Gruppe. „Ganzer Verein“ zeigt zusätzlich Termine
                anderer Gruppen desselben Vereins.
              </p>
              <details className="planning-filter-help">
                <summary className="planning-filter-help__summary">Mehr zu Ansicht &amp; Trainerzuordnung</summary>
                <div className="planning-filter-help__body">
                  <p style={{ margin: '0 0 0.65rem' }}>
                    „Ganzer Verein“ bezieht sich auf denselben Verein wie die gewählte Gruppe. Neu angelegte Termine
                    beziehen sich weiterhin auf die Gruppe, die du oben gewählt hast.
                  </p>
                  {selectedGroupId ? (
                    <p style={{ margin: 0 }}>
                      Über <strong>Trainer</strong> oder <strong>Trainer zuweisen</strong> bearbeitest du Leitung und
                      Co je Einheit (berechtigt: Vereinsorganisation, Haupt-/Co‑Trainer der Gruppe sowie Erstellung
                      der Einheit). Das Mitgliederverzeichnis listet nur eigene Vereinsmitglieder; die Leitung erscheint
                      nicht unter Co‑Trainer.
                    </p>
                  ) : (
                    <p style={{ margin: 0, color: 'var(--text3)' }}>
                      Wähle zuerst eine Gruppe — dann erweitert sich die Hilfe zu Trainer und Berechtigungen.
                    </p>
                  )}
                </div>
              </details>
            </div>
          </div>

          {selectedGroup && (
            <div
              style={{
                marginTop: '1rem',
                padding: '1rem',
                background: 'var(--surface2)',
                borderRadius: '8px'
              }}
            >
              <p style={{ fontSize: '0.875rem', color: 'var(--text2)' }}>
                {selectedGroup.location || 'Kein Ort angegeben'}
                {selectedGroup.weekday && ` · ${selectedGroup.weekday}`}
                {selectedGroup.time_start &&
                  ` · ${selectedGroup.time_start.slice(0, 5)} - ${selectedGroup.time_end?.slice(0, 5)}`}
              </p>
            </div>
          )}

          <div className="training-planning-create training-planning-create--in-card">
            <div className="training-planning-create__intro">
              <h3 className="training-planning-create__title">Neue Trainingseinheit</h3>
              <p className="training-planning-create__lede">
                Datum, Zeiten und Ablauf (Abschnitte &amp; Übungen) — optional{' '}
                <strong>Trainingsvorlage</strong> oder Inhalte aus einem <strong>Rahmenprogramm</strong> im Dialog.
              </p>
              {!selectedGroupId && (
                <p className="training-planning-create__hint training-planning-create__hint--warn">
                  Wähle oben eine Trainingsgruppe, um fortzufahren.
                </p>
              )}
              {groups.length === 0 && (
                <p className="training-planning-create__hint training-planning-create__hint--warn">
                  Es gibt noch keine aktive Trainingsgruppe — unter{' '}
                  <Link to="/clubs">Vereine</Link> anlegen oder aktivieren.
                </p>
              )}
            </div>
            <div className="training-planning-create__actions">
              <button
                type="button"
                className="btn btn-primary training-planning-create__cta"
                disabled={!selectedGroupId}
                title={!selectedGroupId ? 'Zuerst eine Trainingsgruppe wählen' : undefined}
                onClick={handleCreate}
              >
                Trainingseinheit planen…
              </button>
              <button
                type="button"
                className="btn btn-secondary training-planning-create__secondary"
                disabled={!selectedGroupId}
                title={!selectedGroupId ? 'Zuerst eine Trainingsgruppe wählen' : undefined}
                onClick={openFrameworkImportModal}
              >
                Aus Rahmen übernehmen…
              </button>
            </div>
          </div>
        </div>

        {!selectedGroupId ? (
          <div className="card">
            <p style={{ color: 'var(--text2)', textAlign: 'center' }}>
              Wähle oben eine Trainingsgruppe — danach kannst du unter{' '}
              <strong>„Trainingseinheit planen…“</strong> einen Termin anlegen.
            </p>
          </div>
        ) : planView === 'calendar' ? (
          <div className="card" style={{ padding: 'clamp(8px, 2vw, 14px)', overflowX: 'auto' }}>
            {units.length === 0 ? (
              <p style={{ color: 'var(--text2)', fontSize: '0.88rem', margin: '0 0 12px', lineHeight: 1.45 }}>
                Im sichtbaren Monatsbereich liegt noch keine Einheit. Über <strong>+</strong> in einem Tag legst du einen
                neuen Termin mit Datum an.
              </p>
            ) : null}
            <div
              style={{
                display: 'grid',
                gridTemplateColumns: 'repeat(7, minmax(0, 1fr))',
                gap: '4px',
                minWidth: 'min(960px, 100%)',
              }}
              role="grid"
              aria-label={`Kalender ${calendarMonthTitle}`}
            >
              {WEEKDAYS_DE.map((w) => (
                <div
                  key={w}
                  style={{
                    fontWeight: 600,
                    fontSize: '0.72rem',
                    textAlign: 'center',
                    padding: '6px 2px',
                    color: 'var(--text3)',
                  }}
                  role="columnheader"
                >
                  {w}
                </div>
              ))}
              {calendarGridDays.map((dayIso) => {
                const inMonth = dayIso.slice(0, 7) === calendarMonthStr
                const dayNum = parseInt(dayIso.slice(8, 10), 10)
                const isTodayMarker = dayIso === today
                const dayUnits = unitsByPlannedDate.get(dayIso) || []
                return (
                  <div
                    key={dayIso}
                    role="gridcell"
                    style={{
                      minHeight: '96px',
                      border: '1px solid var(--border, rgba(0, 0, 0, 0.1))',
                      borderRadius: '6px',
                      padding: '5px',
                      background: inMonth ? 'var(--surface)' : 'var(--surface2)',
                      opacity: inMonth ? 1 : 0.58,
                      boxShadow: isTodayMarker ? 'inset 0 0 0 2px var(--accent-dark, #256)' : undefined,
                    }}
                  >
                    <div
                      style={{
                        display: 'flex',
                        justifyContent: 'space-between',
                        alignItems: 'flex-start',
                        gap: '4px',
                        marginBottom: '6px',
                      }}
                    >
                      <span style={{ fontWeight: 700, fontSize: '0.82rem', lineHeight: 1 }}>{dayNum}</span>
                      <button
                        type="button"
                        className="btn btn-secondary framework-ctrl framework-ctrl--xs"
                        title={`Neue Trainingseinheit am ${dayIso}`}
                        aria-label={`Neue Trainingseinheit am ${dayIso}`}
                        onClick={() => handleCreateForDate(dayIso)}
                        disabled={!selectedGroupId}
                        style={{ padding: '2px 6px', flexShrink: 0 }}
                      >
                        +
                      </button>
                    </div>
                    <div style={{ display: 'flex', flexDirection: 'column', gap: '4px' }}>
                      {dayUnits.slice(0, 3).map((unit) => (
                        <div
                          key={unit.id}
                          style={{ display: 'flex', flexDirection: 'column', gap: '4px', width: '100%' }}
                        >
                          <button
                            type="button"
                            onClick={() => handleEdit(unit)}
                            title={[
                              planScope === 'club' && unit.group_name ? unit.group_name : '',
                              unit.planned_time_start?.slice(0, 5) || '',
                              unit.lead_trainer_name?.trim(),
                              unit.planned_focus?.trim(),
                              unit.status === 'completed'
                                ? 'Durchgeführt'
                                : unit.status === 'cancelled'
                                  ? 'Abgesagt'
                                  : 'Geplant',
                            ]
                              .filter(Boolean)
                              .join(' · ')}
                            style={{
                              border: 'none',
                              cursor: 'pointer',
                              textAlign: 'left',
                              padding: '4px 5px',
                              borderRadius: '4px',
                              fontSize: '0.7rem',
                              lineHeight: 1.25,
                              width: '100%',
                              borderLeftWidth: '3px',
                              borderLeftStyle: 'solid',
                              borderLeftColor:
                                unit.status === 'completed'
                                  ? '#2ea44f'
                                  : unit.status === 'cancelled'
                                    ? 'var(--danger)'
                                    : 'var(--accent-dark)',
                              background: 'var(--surface2)',
                              color: 'var(--text1)',
                            }}
                          >
                            <span style={{ fontWeight: 600 }}>
                              {unit.planned_time_start
                                ? `${unit.planned_time_start.slice(0, 5)}`
                                : 'Ganztags'}
                            </span>
                            {planScope === 'club' && (unit.group_name || '').trim() ? (
                              <span style={{ display: 'block', fontWeight: 500, color: 'var(--text1)' }}>
                                {(unit.group_name || '').trim().length > 22
                                  ? `${(unit.group_name || '').trim().slice(0, 22)}…`
                                  : unit.group_name}
                              </span>
                            ) : null}
                            {unit.lead_trainer_name?.trim() ? (
                              <span
                                style={{
                                  display: 'block',
                                  color: 'var(--text3)',
                                  fontWeight: 400,
                                  fontSize: '0.62rem',
                                }}
                              >
                                {unit.lead_trainer_name.trim().split(/\s+/).slice(-1)[0] ||
                                  unit.lead_trainer_name.trim()}
                              </span>
                            ) : null}
                            {unit.planned_focus?.trim() ? (
                              <span style={{ display: 'block', color: 'var(--text2)', fontWeight: 400 }}>
                                {(unit.planned_focus || '').trim().length > 24
                                  ? `${(unit.planned_focus || '').trim().slice(0, 24)}…`
                                  : unit.planned_focus}
                              </span>
                            ) : null}
                          </button>
                          {mayConfigureSessionAssignments(unit) ? (
                            <button
                              type="button"
                              className="btn btn-secondary framework-ctrl framework-ctrl--xs"
                              style={{ fontSize: '0.62rem', padding: '2px 4px', alignSelf: 'stretch' }}
                              onClick={(ev) => {
                                ev.stopPropagation()
                                openTrainerAssignModal(unit)
                              }}
                            >
                              Trainer
                            </button>
                          ) : null}
                        </div>
                      ))}
                    </div>
                    {dayUnits.length > 3 ? (
                      <p style={{ fontSize: '0.65rem', color: 'var(--text3)', margin: '4px 0 0', lineHeight: 1.3 }}>
                        +{dayUnits.length - 3} weitere
                      </p>
                    ) : null}
                  </div>
                )
              })}
            </div>
          </div>
        ) : units.length === 0 ? (
          <div className="card">
            <p style={{ color: 'var(--text2)', textAlign: 'center' }}>
              Keine Trainingseinheiten in diesem Zeitraum. Unten unter <strong>„Neue Trainingseinheit“</strong> einen
              Termin anlegen — optional mit Vorlage im Dialog.
            </p>
          </div>
        ) : (
          <div style={{ display: 'grid', gap: '1rem' }}>
            {units.map((unit) => {
              const lineage = unit.origin_framework_slot_id ? frameworkLineageText(unit) : null
              const uid = user?.id != null ? Number(user.id) : null
              const effLead =
                unit.effective_lead_trainer_profile_id != null
                  ? Number(unit.effective_lead_trainer_profile_id)
                  : null
              const showTakeLead =
                unit.status === 'planned' && uid != null && effLead != null && effLead !== uid
              return (
              <div key={unit.id} className="card">
                <div
                  style={{
                    display: 'flex',
                    flexWrap: 'wrap',
                    justifyContent: 'space-between',
                    alignItems: 'flex-start',
                    gap: '12px',
                    marginBottom: '1rem'
                  }}
                >
                  <div style={{ minWidth: 0, flex: '1 1 200px' }}>
                    <h3 style={{ marginBottom: '0.25rem' }}>
                      {unit.planned_date}
                      {unit.planned_time_start &&
                        ` · ${unit.planned_time_start.slice(0, 5)} - ${unit.planned_time_end?.slice(0, 5)}`}
                    </h3>
                    {planScope === 'club' && (unit.group_name || '').trim() ? (
                      <p
                        style={{
                          fontSize: '0.85rem',
                          color: 'var(--text3)',
                          margin: '0 0 0.35rem',
                        }}
                      >
                        {unit.group_name}
                      </p>
                    ) : null}
                    <p style={{ fontSize: '0.82rem', color: 'var(--text2)', margin: '0 0 0.5rem' }}>
                      Leitung: {(unit.lead_trainer_name || '').trim() || '—'}
                    </p>
                    {(() => {
                      const coRaw = unit.effective_assistant_trainer_profile_ids
                      const co = Array.isArray(coRaw)
                        ? coRaw.map(Number).filter((x) => Number.isFinite(x) && x >= 1)
                        : []
                      if (!co.length) return null
                      const src =
                        unit.assistant_trainer_profile_ids != null
                          ? 'Session-Zuweisung'
                          : 'über Trainingsgruppe'
                      return (
                        <p
                          style={{
                            fontSize: '0.78rem',
                            color: 'var(--text3)',
                            margin: '0 0 0.5rem',
                          }}
                        >
                          Co-Trainer ({src}): {co.length}
                        </p>
                      )
                    })()}
                    {unit.planned_focus && (
                      <p
                        style={{
                          color: 'var(--text2)',
                          fontSize: '0.875rem',
                          marginBottom: '0.5rem'
                        }}
                      >
                        Fokus: {unit.planned_focus}
                      </p>
                    )}
                    {lineage ? (
                      <p
                        style={{
                          color: 'var(--text2)',
                          fontSize: '0.82rem',
                          marginBottom: '0.5rem',
                          lineHeight: 1.45,
                        }}
                      >
                        <span style={{ fontWeight: 600, color: 'var(--text3)' }}>Aus Rahmen: </span>
                        {unit.origin_framework_program_id ? (
                          <Link
                            to={`/planning/framework-programs/${unit.origin_framework_program_id}`}
                            style={{ color: 'var(--accent-dark)' }}
                          >
                            {lineage.fpTitle}
                          </Link>
                        ) : (
                          <span>{lineage.fpTitle}</span>
                        )}
                        <span style={{ color: 'var(--text2)' }}> · {lineage.slotBit}</span>
                      </p>
                    ) : null}
                    <div style={{ display: 'flex', gap: '0.5rem', flexWrap: 'wrap' }}>
                      <span
                        style={{
                          fontSize: '0.75rem',
                          padding: '0.25rem 0.5rem',
                          borderRadius: '4px',
                          background:
                            unit.status === 'completed'
                              ? '#2ea44f'
                              : unit.status === 'cancelled'
                                ? 'var(--danger)'
                                : 'var(--surface2)',
                          color:
                            unit.status === 'completed' || unit.status === 'cancelled'
                              ? 'white'
                              : 'var(--text2)'
                        }}
                      >
                        {unit.status === 'planned' && 'Geplant'}
                        {unit.status === 'completed' && 'Durchgeführt'}
                        {unit.status === 'cancelled' && 'Abgesagt'}
                      </span>
                      {unit.attendance_count !== null && unit.attendance_count !== undefined && (
                        <span
                          style={{
                            fontSize: '0.75rem',
                            padding: '0.25rem 0.5rem',
                            borderRadius: '4px',
                            background: 'var(--surface2)',
                            color: 'var(--text2)'
                          }}
                        >
                          {unit.attendance_count} Teilnehmer
                        </span>
                      )}
                    </div>
                  </div>

                  <div
                    style={{
                      display: 'flex',
                      gap: '0.5rem',
                      flexWrap: 'wrap',
                      justifyContent: 'flex-end',
                      flex: '1 1 180px',
                      minWidth: 0
                    }}
                  >
                    <Link
                      to={`/planning/run/${unit.id}`}
                      className="btn btn-secondary"
                      style={{ textDecoration: 'none', display: 'inline-flex', alignItems: 'center', justifyContent: 'center' }}
                    >
                      Plan &amp; Ablauf
                    </Link>
                    <Link
                      to={`/planning/run/${unit.id}/coach`}
                      className="btn btn-primary"
                      style={{ textDecoration: 'none', display: 'inline-flex', alignItems: 'center', justifyContent: 'center' }}
                    >
                      Im Training (Coach)
                    </Link>
                    <button className="btn btn-secondary" onClick={() => handleEdit(unit)}>
                      Bearbeiten
                    </button>
                    {mayConfigureSessionAssignments(unit) ? (
                      <button
                        type="button"
                        className="btn btn-secondary"
                        onClick={() => openTrainerAssignModal(unit)}
                        title="Nur organisatorisch: Leitung und Co für diese Einheit"
                      >
                        Trainer zuweisen
                      </button>
                    ) : null}
                    {showTakeLead ? (
                      <button type="button" className="btn btn-secondary" onClick={() => handleTakeLead(unit)}>
                        Ich übernehme
                      </button>
                    ) : null}
                    <button
                      className="btn"
                      style={{ background: 'var(--danger)', color: 'white', border: 'none' }}
                      onClick={() => handleDelete(unit)}
                    >
                      Löschen
                    </button>
                  </div>
                </div>

                {unit.notes && (
                  <p style={{ color: 'var(--text2)', fontSize: '0.875rem', marginTop: '0.5rem' }}>
                    {unit.notes}
                  </p>
                )}
              </div>
              )
            })}
          </div>
        )}

        {assignModalOpen && assignDraft.unit ? (
          <div
            style={{
              position: 'fixed',
              top: 0,
              left: 0,
              right: 0,
              bottom: 0,
              background: 'rgba(0,0,0,0.5)',
              display: 'flex',
              alignItems: 'center',
              justifyContent: 'center',
              zIndex: 1020,
              padding: '1rem',
              overflowY: 'auto',
            }}
            role="presentation"
            onClick={() => {
              if (!assignSaving) setAssignModalOpen(false)
            }}
          >
            <div
              role="dialog"
              aria-modal="true"
              aria-labelledby="trainer-assign-modal-title"
              onClick={(e) => e.stopPropagation()}
              style={{
                background: 'var(--surface)',
                borderRadius: '12px',
                padding: 'clamp(14px, 3vw, 1.75rem)',
                maxWidth: 'min(460px, 100%)',
                width: '100%',
                maxHeight: '90vh',
                overflowY: 'auto',
                boxSizing: 'border-box',
              }}
            >
              <h2 id="trainer-assign-modal-title" style={{ marginBottom: '0.5rem', fontSize: '1.1rem' }}>
                Trainer zuweisen (organisatorisch)
              </h2>
              <p style={{ fontSize: '0.86rem', color: 'var(--text2)', marginBottom: '1rem', lineHeight: 1.45 }}>
                {(assignDraft.unit.planned_date || '').toString().slice(0, 10)}
                {assignDraft.unit.planned_time_start
                  ? ` · ${String(assignDraft.unit.planned_time_start).slice(0, 5)}`
                  : ''}
                {(assignDraft.unit.group_name || '').trim()
                  ? ` · ${(assignDraft.unit.group_name || '').trim()}`
                  : null}
              </p>
              <div className="form-row">
                <label className="form-label">Leitung (diese Einheit)</label>
                <select
                  className="form-input"
                  value={assignDraft.lead_trainer_profile_id}
                  onChange={(e) => {
                    const v = e.target.value
                    setAssignDraft((prev) => {
                      const exclude = []
                      const tr = String(v || '').trim()
                      if (tr !== '') {
                        const n = parseInt(tr, 10)
                        if (Number.isFinite(n)) exclude.push(n)
                      } else if (prev.unit?.effective_lead_trainer_profile_id != null) {
                        const ef = Number(prev.unit.effective_lead_trainer_profile_id)
                        if (Number.isFinite(ef)) exclude.push(ef)
                      }
                      const exSet = new Set(exclude)
                      const co = exclude.length
                        ? prev.session_assistant_profile_ids.filter((x) => !exSet.has(x))
                        : prev.session_assistant_profile_ids
                      return { ...prev, lead_trainer_profile_id: v, session_assistant_profile_ids: co }
                    })
                  }}
                  disabled={assignSaving}
                >
                  <option value="">Standard (Haupttrainer der Gruppe)</option>
                  {clubDirectory.map((m) => {
                    const idStr = String(m.id)
                    return (
                      <option key={idStr} value={idStr}>
                        {(m.name || '').trim() || m.email || `Profil ${m.id}`}
                      </option>
                    )
                  })}
                </select>
              </div>
              <div className="form-row" style={{ marginTop: '0.85rem' }}>
                <label style={{ display: 'flex', alignItems: 'center', gap: '8px', cursor: 'pointer' }}>
                  <input
                    type="checkbox"
                    checked={assignDraft.session_assistants_inherit}
                    disabled={assignSaving}
                    onChange={(e) =>
                      setAssignDraft((prev) => ({
                        ...prev,
                        session_assistants_inherit: e.target.checked,
                      }))
                    }
                  />
                  <span style={{ fontSize: '0.9rem', color: 'var(--text1)' }}>
                    Co-Trainer wie in der Trainingsgruppe
                  </span>
                </label>
              </div>
              {!assignDraft.session_assistants_inherit ? (
                <div style={{ marginTop: '10px', maxHeight: '180px', overflowY: 'auto' }}>
                  {clubDirectoryForAssignCo.map((m) => {
                    const mid = typeof m.id === 'number' ? m.id : parseInt(String(m.id), 10)
                    const labelText = `${(m.name || '').trim() || m.email || `Profil ${mid}`}`
                    const isOn = Number.isFinite(mid) && assignDraft.session_assistant_profile_ids.includes(mid)
                    return (
                      <label
                        key={`assign-co-${mid}`}
                        style={{
                          display: 'flex',
                          alignItems: 'center',
                          gap: '8px',
                          fontSize: '0.875rem',
                          marginBottom: '6px',
                          cursor: assignSaving ? 'default' : 'pointer',
                          color: 'var(--text1)',
                        }}
                      >
                        <input
                          type="checkbox"
                          checked={isOn}
                          disabled={assignSaving}
                          onChange={() => {
                            setAssignDraft((prev) => {
                              const was = prev.session_assistant_profile_ids.includes(mid)
                              const nextIds = was
                                ? prev.session_assistant_profile_ids.filter((x) => x !== mid)
                                : [...prev.session_assistant_profile_ids, mid].sort((a, b) => a - b)
                              return { ...prev, session_assistant_profile_ids: nextIds }
                            })
                          }}
                        />
                        <span>{labelText}</span>
                      </label>
                    )
                  })}
                </div>
              ) : null}
              {!clubDirectory.length ? (
                <p style={{ marginTop: '10px', fontSize: '0.82rem', color: 'var(--text3)' }}>
                  Mitgliederverzeichnis konnte nicht geladen werden.
                </p>
              ) : null}
              <div
                style={{
                  display: 'flex',
                  gap: '0.65rem',
                  flexWrap: 'wrap',
                  justifyContent: 'flex-end',
                  marginTop: '1.25rem',
                }}
              >
                <button
                  type="button"
                  className="btn btn-secondary"
                  disabled={assignSaving}
                  onClick={() => setAssignModalOpen(false)}
                >
                  Abbrechen
                </button>
                <button type="button" className="btn btn-primary" disabled={assignSaving} onClick={saveTrainerAssignModal}>
                  {assignSaving ? 'Speichern …' : 'Speichern'}
                </button>
              </div>
            </div>
          </div>
        ) : null}

        {moduleApplyOpen && (
          <div
            style={{
              position: 'fixed',
              top: 0,
              left: 0,
              right: 0,
              bottom: 0,
              background: 'rgba(0,0,0,0.5)',
              display: 'flex',
              alignItems: 'center',
              justifyContent: 'center',
              zIndex: 1010,
              padding: '1rem',
              overflowY: 'auto',
            }}
            role="presentation"
            onMouseDown={(ev) => {
              if (ev.target !== ev.currentTarget || moduleApplyBusy) return
              setModuleApplyOpen(false)
              setModuleApplyPlacementLocked(false)
            }}
          >
            <div
              className="card"
              style={{
                padding: 'clamp(14px, 3vw, 1.75rem)',
                maxWidth: 'min(560px, 100%)',
                width: '100%',
                maxHeight: '90vh',
                overflowY: 'auto',
                boxSizing: 'border-box',
              }}
              role="dialog"
              aria-labelledby="module-apply-title"
            >
              <h2 id="module-apply-title" style={{ marginBottom: '0.5rem', fontSize: '1.15rem' }}>
                Trainingsmodul einfügen
              </h2>
              <p style={{ color: 'var(--text2)', fontSize: '0.87rem', marginBottom: '0.85rem', lineHeight: 1.5 }}>
                Alle Positionen des gewählten Moduls werden <strong>als neue Zeilen</strong> eingefügt (Kopie, mit klarer
                Herkunft im Ablauf). Die Einheit brauchst du dafür nicht vorher gespeichert zu haben — Speichern am Ende
                wie gewohnt. <strong>Vollständige Textsuche oder Modulkategorien</strong> planen wir serverseitig für
                eine spätere Iteration; vorerst steht hier eine{' '}
                <strong>Schnellsuche über Titel und Freitext-Felder</strong> zur Verfügung.
              </p>

              {moduleApplyErr ? (
                <p style={{ color: 'var(--danger)', fontSize: '0.9rem', marginBottom: '0.75rem' }}>{moduleApplyErr}</p>
              ) : null}

              {moduleApplyPlacementLocked ? (
                <>
                  <p style={{ margin: '0 0 0.75rem', fontSize: '0.85rem', lineHeight: 1.5, color: 'var(--text2)' }}>
                    Aktuelle Einfügeposition: Abschnitt <strong>{modulePlacementSummary.secTitle}</strong>{' '}
                    <span aria-hidden>/</span> {modulePlacementSummary.positionDescription}
                  </p>
                  <details className="tu-module-apply-placement-details">
                    <summary style={{ outline: 'none' }}>Abschnitt oder Position ändern</summary>
                    <div style={{ marginTop: '0.75rem', display: 'flex', flexDirection: 'column', gap: '0.85rem' }}>
                      <div className="form-row" style={{ marginBottom: 0 }}>
                        <label className="form-label">Abschnitt (Reihenfolge wie im Editor)</label>
                        <select
                          className="form-input"
                          value={String(moduleApplySectionIx)}
                          onChange={(e) => {
                            const newIx = parseInt(e.target.value, 10)
                            setModuleApplySectionIx(newIx)
                            const secsNow = planningFormRef.current?.sections ?? []
                            const len = Array.isArray(secsNow[newIx]?.items) ? secsNow[newIx].items.length : 0
                            setModuleApplyInsertSlot(`before:${len}`)
                          }}
                          disabled={moduleApplyBusy || !formData.sections?.length}
                        >
                          {(formData.sections || []).map((s, i) => (
                            <option key={`sec-opt-u-${i}`} value={String(i)}>
                              {(s.title || `Abschnitt ${i + 1}`).trim()}
                            </option>
                          ))}
                        </select>
                      </div>
                      <div className="form-row" style={{ marginBottom: 0 }}>
                        <label className="form-label">Position in diesem Abschnitt</label>
                        <select
                          className="form-input"
                          value={moduleApplyInsertSlot}
                          onChange={(e) => setModuleApplyInsertSlot(e.target.value)}
                          disabled={moduleApplyBusy || !(formData.sections?.length > 0)}
                        >
                          <option value={`before:${moduleApplyTargetItems.length}`}>
                            Am Ende einfügen (nach allen Einträgen)
                          </option>
                          <option value="before:0">An den Anfang (vor dem ersten Eintrag)</option>
                          {moduleApplyTargetItems.map((row, xi) => {
                            const labelPart =
                              row.item_type === 'note'
                                ? 'Zwischen-Anmerkung'
                                : (row.exercise_title || '').trim() || `Übung #${row.exercise_id || '—'}`
                            const clipped =
                              labelPart.length > 44 ? `${labelPart.slice(0, 43).trim()}…` : labelPart
                            return (
                              <option key={`before-u-${xi}`} value={`before:${xi}`}>
                                Vor Eintrag {xi + 1}: {clipped}
                              </option>
                            )
                          })}
                        </select>
                      </div>
                    </div>
                  </details>
                </>
              ) : (
                <>
                  <div className="form-row">
                    <label className="form-label">Abschnitt (Reihenfolge wie im Editor)</label>
                    <select
                      className="form-input"
                      value={String(moduleApplySectionIx)}
                      onChange={(e) => {
                        const newIx = parseInt(e.target.value, 10)
                        setModuleApplySectionIx(newIx)
                        const secsNow = planningFormRef.current?.sections ?? []
                        const len = Array.isArray(secsNow[newIx]?.items) ? secsNow[newIx].items.length : 0
                        setModuleApplyInsertSlot(`before:${len}`)
                      }}
                      disabled={moduleApplyBusy || !formData.sections?.length}
                    >
                      {(formData.sections || []).map((s, i) => (
                        <option key={`sec-opt-${i}`} value={String(i)}>
                          {(s.title || `Abschnitt ${i + 1}`).trim()}
                        </option>
                      ))}
                    </select>
                  </div>

                  <div className="form-row">
                    <label className="form-label">Position in diesem Abschnitt</label>
                    <select
                      className="form-input"
                      value={moduleApplyInsertSlot}
                      onChange={(e) => setModuleApplyInsertSlot(e.target.value)}
                      disabled={moduleApplyBusy || !(formData.sections?.length > 0)}
                    >
                      <option value={`before:${moduleApplyTargetItems.length}`}>
                        Am Ende einfügen (nach allen Einträgen)
                      </option>
                      <option value="before:0">An den Anfang (vor dem ersten Eintrag)</option>
                      {moduleApplyTargetItems.map((row, xi) => {
                        const labelPart =
                          row.item_type === 'note'
                            ? 'Zwischen-Anmerkung'
                            : (row.exercise_title || '').trim() || `Übung #${row.exercise_id || '—'}`
                        const clipped =
                          labelPart.length > 44 ? `${labelPart.slice(0, 43).trim()}…` : labelPart
                        return (
                          <option key={`before-${xi}`} value={`before:${xi}`}>
                            Vor Eintrag {xi + 1}: {clipped}
                          </option>
                        )
                      })}
                    </select>
                  </div>
                </>
              )}

              <div className="form-row" style={{ marginTop: moduleApplyPlacementLocked ? '1rem' : undefined }}>
                <label className="form-label">Suche Module</label>
                <input
                  type="search"
                  enterKeyHint="search"
                  className="form-input tu-modulepick-search"
                  placeholder="Freitext: Titel, Kurzbeschreibung, Ziel, Zielgruppe …"
                  value={moduleApplySearchQuery}
                  onChange={(e) => setModuleApplySearchQuery(e.target.value)}
                  disabled={moduleApplyBusy}
                  aria-label="Module durch Freitext filtern"
                />
              </div>

              <div className="form-row" style={{ marginBottom: '0.65rem' }}>
                <label className="form-label" id="module-pick-label">
                  Modulliste
                </label>
              </div>
              <div
                className="tu-modulepick-list"
                role="listbox"
                aria-labelledby="module-pick-label"
                aria-activedescendant={
                  moduleApplyModuleId ? `module-pick-opt-${moduleApplyModuleId}` : undefined
                }
              >
                {!moduleApplyFilteredList.length ? (
                  <p style={{ margin: '0.45rem', fontSize: '0.86rem', color: 'var(--text3)', lineHeight: 1.45 }}>
                    {!moduleApplyList.length ? 'Keine Module verfügbar oder keine Berechtigung.' : 'Kein Modul entspricht der Suche.'}
                  </p>
                ) : (
                  moduleApplyFilteredList.map((m) => {
                    const title = ((m.title || '').trim() || `Modul #${m.id}`).trim()
                    const visLbl = trainingVisibilityShortDE(m.visibility)
                    const nPos = typeof m.items_count === 'number' ? m.items_count : '—'
                    const selected = String(m.id) === String(moduleApplyModuleId)
                    return (
                      <button
                        key={m.id}
                        id={`module-pick-opt-${m.id}`}
                        type="button"
                        role="option"
                        aria-selected={selected}
                        className={`tu-modulepick-item${selected ? ' tu-modulepick-item--active' : ''}`}
                        disabled={moduleApplyBusy}
                        onClick={() => setModuleApplyModuleId(String(m.id))}
                      >
                        <span className="tu-modulepick-item__title">{title}</span>
                        <span className="tu-modulepick-item__meta">
                          {nPos} {typeof nPos === 'number' ? (nPos === 1 ? 'Position' : 'Positionen') : 'Position(en)'}
                          {visLbl ? <> · {visLbl}</> : null}
                          {m.summary ? <> · {(m.summary || '').trim().slice(0, 72)}{(m.summary || '').trim().length > 72 ? '…' : ''}</> : null}
                        </span>
                      </button>
                    )
                  })
                )}
              </div>

              {moduleApplyModuleId ? (
                <div className="tu-modulepick-preview" aria-live="polite">
                  <div className="tu-modulepick-preview__title">Ablauf-Vorschau (Bibliotheksmodul)</div>
                  {modulePickPreview.loading ? (
                    <p style={{ margin: '0.15rem 0 0', fontSize: '0.86rem', color: 'var(--text3)' }}>
                      Übungen und Hinweise laden …
                    </p>
                  ) : modulePickPreview.err ? (
                    <p style={{ margin: '0.15rem 0 0', fontSize: '0.86rem', color: 'var(--danger)' }}>
                      {modulePickPreview.err}
                    </p>
                  ) : !modulePickPreview.exercises.length && !modulePickPreview.notes ? (
                    <p style={{ margin: '0.15rem 0 0', fontSize: '0.86rem', color: 'var(--text3)' }}>
                      Keine Übungspositionen in diesem Eintrag gefunden (prüfen, ob Übungen im Modul gültige IDs haben).
                    </p>
                  ) : (
                    <>
                      <ol className="tu-modulepick-preview__list">
                        {(modulePickPreview.exercises.slice(0, 12)).map((t, qi) => (
                          <li key={`pv-ex-${qi}`}>{t}</li>
                        ))}
                      </ol>
                      {modulePickPreview.exercises.length > 12 ? (
                        <p className="tu-modulepick-preview__more">
                          … und noch {modulePickPreview.exercises.length - 12} weitere Übungen in genau dieser Modulreihenfolge.
                        </p>
                      ) : null}
                      {modulePickPreview.notes > 0 ? (
                        <p className="tu-modulepick-preview__more">
                          zusätzlich {modulePickPreview.notes}{' '}
                          {modulePickPreview.notes === 1 ? 'Position mit Hinweis' : 'Positionen mit Hinweisen'}{' '}
                          (ohne Aufzählung)
                        </p>
                      ) : null}
                    </>
                  )}
                </div>
              ) : null}

              <div
                style={{
                  display: 'flex',
                  gap: '0.65rem',
                  flexWrap: 'wrap',
                  justifyContent: 'flex-end',
                  marginTop: '1.25rem',
                }}
              >
                <button
                  type="button"
                  className="btn btn-secondary"
                  disabled={moduleApplyBusy}
                  onClick={() => {
                    if (moduleApplyBusy) return
                    setModuleApplyOpen(false)
                    setModuleApplyPlacementLocked(false)
                  }}
                >
                  Abbrechen
                </button>
                <button type="button" className="btn btn-primary" disabled={moduleApplyBusy} onClick={handleApplyTrainingModuleConfirm}>
                  {moduleApplyBusy ? 'Einfügen …' : 'Einfügen'}
                </button>
              </div>

              <p style={{ margin: '1rem 0 0', fontSize: '0.8rem', color: 'var(--text3)', lineHeight: 1.45 }}>
                Neue Module kannst du unter{' '}
                <Link to="/planning/training-modules" style={{ fontWeight: 600, color: 'var(--accent-dark)' }}>
                  Trainingsmodule
                </Link>{' '}
                anlegen.
              </p>
            </div>
          </div>
        )}

        {frameworkImportOpen && (
          <div
            style={{
              position: 'fixed',
              top: 0,
              left: 0,
              right: 0,
              bottom: 0,
              background: 'rgba(0,0,0,0.5)',
              display: 'flex',
              alignItems: 'center',
              justifyContent: 'center',
              zIndex: 1010,
              padding: '1rem',
              overflowY: 'auto',
            }}
          >
            <div
              style={{
                background: 'var(--surface)',
                borderRadius: '12px',
                padding: 'clamp(14px, 3vw, 1.75rem)',
                maxWidth: 'min(620px, 100%)',
                width: '100%',
                maxHeight: '90vh',
                overflowY: 'auto',
                boxSizing: 'border-box',
                minWidth: 0,
              }}
            >
              <h2 style={{ marginBottom: '0.65rem' }}>Sessions aus Rahmen übernehmen</h2>
              <p style={{ color: 'var(--text2)', fontSize: '0.9rem', marginBottom: '1rem', lineHeight: 1.5 }}>
                Wähle ein Trainingsrahmenprogramm und eine oder mehrere Sessions. Pro Session entsteht eine{' '}
                <strong>eigene geplante Einheit</strong> in der aktuellen Gruppe (Kopie des Ablaufs). Die{' '}
                <strong>Verknüpfung zum Rahmen-Slot</strong> wird gespeichert, damit die Herkunft sichtbar bleibt.
              </p>

              <div className="form-row">
                <label className="form-label">Rahmenprogramm</label>
                <select
                  className="form-input"
                  value={fwImportProgramId}
                  onChange={(e) => onFwImportProgramChange(e.target.value)}
                  disabled={fwImportLoading || fwImportSubmitting}
                >
                  <option value="">Bitte wählen…</option>
                  {frameworkProgramsList.map((fp) => (
                    <option key={fp.id} value={String(fp.id)}>
                      {(fp.title || '').trim() || `Rahmen #${fp.id}`}
                    </option>
                  ))}
                </select>
              </div>

              {fwImportLoading ? (
                <p style={{ color: 'var(--text2)', marginTop: '1rem' }}>Laden der Sessions…</p>
              ) : fwImportDetail?.slots?.length ? (
                <>
                  <fieldset style={{ border: 'none', margin: '1rem 0', padding: 0 }}>
                    <legend className="form-label" style={{ padding: 0, marginBottom: '0.5rem' }}>
                      Sessions (mit Ablauf)
                    </legend>
                    <ul style={{ listStyle: 'none', padding: 0, margin: 0 }}>
                      {[...fwImportDetail.slots]
                        .sort((a, b) => (a.sort_order ?? 0) - (b.sort_order ?? 0))
                        .map((slot) => {
                          const hasBp = !!slot.blueprint_training_unit_id
                          const checked = fwImportSelectedSlots.has(slot.id)
                          const label =
                            (slot.title || '').trim() ||
                            `Session ${(slot.sort_order ?? 0) + 1}`
                          return (
                            <li key={slot.id} style={{ marginBottom: '10px' }}>
                              <label
                                style={{
                                  display: 'flex',
                                  gap: '10px',
                                  alignItems: 'flex-start',
                                  cursor: hasBp ? 'pointer' : 'not-allowed',
                                  opacity: hasBp ? 1 : 0.55,
                                }}
                              >
                                <input
                                  type="checkbox"
                                  checked={checked}
                                  disabled={!hasBp || fwImportSubmitting}
                                  onChange={() => toggleFwImportSlot(slot)}
                                  style={{ marginTop: '0.2rem', flexShrink: 0 }}
                                />
                                <span style={{ flex: 1, minWidth: 0 }}>
                                  <strong>{label}</strong>
                                  {!hasBp ? (
                                    <span style={{ display: 'block', fontSize: '0.82rem', color: 'var(--danger)' }}>
                                      Ohne Session-Ablauf — Übernahme nicht möglich.
                                    </span>
                                  ) : null}
                                  {hasBp && checked ? (
                                    <span style={{ display: 'block', marginTop: '6px' }}>
                                      <span className="form-label" style={{ fontSize: '0.78rem' }}>
                                        Termin (Datum)
                                      </span>
                                      <input
                                        type="date"
                                        className="form-input"
                                        style={{ maxWidth: '200px', marginTop: '4px' }}
                                        value={fwImportSlotDates[String(slot.id)] || ''}
                                        onChange={(e) =>
                                          setFwImportSlotDates((prev) => ({
                                            ...prev,
                                            [String(slot.id)]: e.target.value,
                                          }))
                                        }
                                        disabled={fwImportSubmitting}
                                      />
                                    </span>
                                  ) : null}
                                </span>
                              </label>
                            </li>
                          )
                        })}
                    </ul>
                  </fieldset>

                  <div
                    className="responsive-grid-3"
                    style={{
                      marginBottom: '0.75rem',
                      padding: '12px',
                      background: 'var(--surface2)',
                      borderRadius: '8px',
                    }}
                  >
                    <div className="form-row">
                      <label className="form-label">Startdatum (Vorschlag)</label>
                      <input
                        type="date"
                        className="form-input"
                        value={fwImportStartDate}
                        onChange={(e) => setFwImportStartDate(e.target.value)}
                        disabled={fwImportSubmitting}
                      />
                    </div>
                    <div className="form-row">
                      <label className="form-label">Abstand (Tage)</label>
                      <input
                        type="number"
                        min={0}
                        className="form-input"
                        value={fwImportIntervalDays}
                        onChange={(e) => setFwImportIntervalDays(parseInt(e.target.value, 10) || 0)}
                        disabled={fwImportSubmitting}
                      />
                    </div>
                    <div className="form-row" style={{ alignSelf: 'end' }}>
                      <button
                        type="button"
                        className="btn btn-secondary"
                        style={{ width: '100%' }}
                        disabled={fwImportSubmitting}
                        onClick={applyFwImportDateSuggestions}
                      >
                        Datumsvorschläge setzen
                      </button>
                    </div>
                  </div>
                </>
              ) : fwImportProgramId ? (
                <p style={{ color: 'var(--text2)', marginTop: '0.75rem' }}>Keine Sessions in diesem Programm.</p>
              ) : null}

              <div style={{ display: 'flex', flexWrap: 'wrap', gap: '0.5rem', marginTop: '1.25rem' }}>
                <button
                  type="button"
                  className="btn btn-primary"
                  disabled={fwImportSubmitting || !fwImportDetail}
                  onClick={submitFrameworkImport}
                >
                  {fwImportSubmitting ? 'Übernehmen…' : 'In Planung übernehmen'}
                </button>
                <button
                  type="button"
                  className="btn btn-secondary"
                  disabled={fwImportSubmitting}
                  onClick={() => setFrameworkImportOpen(false)}
                >
                  Abbrechen
                </button>
              </div>
            </div>
          </div>
        )}

        {showModal && (
          <div
            style={{
              position: 'fixed',
              top: 0,
              left: 0,
              right: 0,
              bottom: 0,
              background: 'rgba(0,0,0,0.5)',
              display: 'flex',
              alignItems: 'center',
              justifyContent: 'center',
              zIndex: 1000,
              padding: '1rem',
              overflowY: 'auto'
            }}
          >
            <div
              style={{
                background: 'var(--surface)',
                borderRadius: '12px',
                padding: 'clamp(12px, 3vw, 2rem)',
                maxWidth: 'min(1100px, 100%)',
                width: '100%',
                maxHeight: '92vh',
                overflowY: 'auto',
                margin: 'max(0px, env(safe-area-inset-top, 0px)) auto',
                boxSizing: 'border-box',
                minWidth: 0
              }}
            >
              <h2 style={{ marginBottom: '1rem' }}>
                {editingUnit ? 'Trainingseinheit bearbeiten' : 'Neue Trainingseinheit'}
              </h2>

              {editingUnit?.origin_framework_slot_id ? (() => {
                const L = frameworkLineageText(editingUnit)
                return (
                  <div
                    className="card"
                    style={{
                      marginBottom: '1.1rem',
                      padding: '12px 14px',
                      background: 'var(--surface2)',
                      fontSize: '0.9rem',
                      lineHeight: 1.5,
                    }}
                  >
                    <strong style={{ color: 'var(--text1)' }}>Herkunft:</strong>{' '}
                    {editingUnit.origin_framework_program_id ? (
                      <Link
                        to={`/planning/framework-programs/${editingUnit.origin_framework_program_id}`}
                        style={{ color: 'var(--accent-dark)' }}
                      >
                        {L.fpTitle}
                      </Link>
                    ) : (
                      L.fpTitle
                    )}
                    <span style={{ color: 'var(--text2)' }}> · {L.slotBit}</span>
                    <p style={{ margin: '0.5rem 0 0', fontSize: '0.82rem', color: 'var(--text2)' }}>
                      Inhalt stammt aus dem Session-Blueprint des Rahmenprogramms. Änderungen gelten nur für diese
                      geplante Einheit; die Zuordnung zum Rahmen bleibt zur Nachverfolgung erhalten.
                    </p>
                  </div>
                )
              })() : null}

              {!editingUnit && (
                <div className="training-planning-template-panel" style={{ marginBottom: '1.35rem' }}>
                  <label className="form-label training-planning-template-panel__label" htmlFor="planning-draft-template">
                    Vorlage für den Ablauf
                  </label>
                  <select
                    id="planning-draft-template"
                    className="form-input training-planning-template-panel__select"
                    value={draftPlanTemplateId}
                    onChange={(e) => applyTemplateFromSelect(e.target.value)}
                  >
                    <option value="">Ohne Vorlage — leere Gliederung (ein Abschnitt)</option>
                    {planTemplates.map((t) => (
                      <option key={t.id} value={String(t.id)}>
                        {t.name}
                        {typeof t.sections_count === 'number' ? ` · ${t.sections_count} Abschn.` : ''}
                      </option>
                    ))}
                  </select>
                  <p className="training-planning-template-panel__help">
                    Übernimmt nur die <strong>Sektionsstruktur</strong> aus der Bibliothek; Übungen trägst du unten bei
                    den Abschnitten ein. Gespeicherte Vorlagen kannst du unter Planung später erweitern.
                  </p>
                </div>
              )}

              <form onSubmit={handleSubmit}>
                <h3 style={{ marginBottom: '1rem' }}>Planung</h3>

                <div className="responsive-grid-3" style={{ marginBottom: '1rem' }}>
                  <div className="form-row">
                    <label className="form-label">Datum *</label>
                    <input
                      type="date"
                      className="form-input"
                      value={formData.planned_date}
                      onChange={(e) => updateFormField('planned_date', e.target.value)}
                      required
                    />
                  </div>

                  <div className="form-row">
                    <label className="form-label">Von</label>
                    <input
                      type="time"
                      className="form-input"
                      value={formData.planned_time_start}
                      onChange={(e) => updateFormField('planned_time_start', e.target.value)}
                    />
                  </div>

                  <div className="form-row">
                    <label className="form-label">Bis</label>
                    <input
                      type="time"
                      className="form-input"
                      value={formData.planned_time_end}
                      onChange={(e) => updateFormField('planned_time_end', e.target.value)}
                    />
                  </div>
                </div>

                <div className="form-row">
                  <label className="form-label">Trainingsfokus</label>
                  <input
                    type="text"
                    className="form-input"
                    value={formData.planned_focus}
                    onChange={(e) => updateFormField('planned_focus', e.target.value)}
                    placeholder="z.B. Grundlagen, Kinder altersgerecht"
                  />
                </div>

                <div
                  className="card"
                  style={{
                    marginTop: '1.25rem',
                    marginBottom: '0.25rem',
                    padding: '12px 14px',
                    background: 'var(--surface2)',
                  }}
                >
                  <h3 style={{ margin: '0 0 10px', fontSize: '1rem' }}>Trainerzuordnung (diese Einheit)</h3>
                  <div className="form-row">
                    <label className="form-label">Leitung</label>
                    <select
                      className="form-input"
                      value={formData.lead_trainer_profile_id}
                      onChange={(e) => updateFormField('lead_trainer_profile_id', e.target.value)}
                      disabled={!editingUnit && !formData.group_id}
                    >
                      <option value="">Standard (Haupttrainer der Gruppe)</option>
                      {clubDirectory.map((m) => {
                        const idStr = String(m.id)
                        return (
                          <option key={idStr} value={idStr}>
                            {(m.name || '').trim() || m.email || `Profil ${m.id}`}
                          </option>
                        )
                      })}
                    </select>
                    <p style={{ fontSize: '0.8rem', color: 'var(--text2)', marginTop: '0.35rem', lineHeight: 1.45 }}>
                      Für Vertretungen genügt in der Regel die Vereinsmitgliedschaft; Zuweisen dürfen u. a.
                      Haupt-/Co‑Trainer dieser Gruppe, der/die Ersteller:in der Einheit oder Vereinsadmins.
                    </p>
                  </div>
                  <div className="form-row" style={{ marginTop: '0.75rem' }}>
                    <label style={{ display: 'flex', alignItems: 'center', gap: '8px', cursor: 'pointer' }}>
                      <input
                        type="checkbox"
                        checked={formData.session_assistants_inherit}
                        onChange={(e) =>
                          updateFormField('session_assistants_inherit', e.target.checked)
                        }
                      />
                      <span style={{ fontSize: '0.9rem', color: 'var(--text1)' }}>
                        Co-Trainer wie in der Trainingsgruppe (Standard)
                      </span>
                    </label>
                  </div>
                  {!formData.session_assistants_inherit ? (
                    <div style={{ marginTop: '10px', maxHeight: '200px', overflowY: 'auto' }}>
                      {clubDirectoryForCo.map((m) => {
                        const mid = typeof m.id === 'number' ? m.id : parseInt(String(m.id), 10)
                        const labelText = `${(m.name || '').trim() || m.email || `Profil ${mid}`}`
                        const isOn = Number.isFinite(mid) && formData.session_assistant_profile_ids.includes(mid)
                        return (
                          <label
                            key={`co-${mid}`}
                            style={{
                              display: 'flex',
                              alignItems: 'center',
                              gap: '8px',
                              fontSize: '0.875rem',
                              marginBottom: '6px',
                              cursor: 'pointer',
                              color: 'var(--text1)',
                            }}
                          >
                            <input
                              type="checkbox"
                              checked={isOn}
                              onChange={() => {
                                setFormData((prev) => {
                                  const was = prev.session_assistant_profile_ids.includes(mid)
                                  const nextIds = was
                                    ? prev.session_assistant_profile_ids.filter((x) => x !== mid)
                                    : [...prev.session_assistant_profile_ids, mid].sort((a, b) => a - b)
                                  return { ...prev, session_assistant_profile_ids: nextIds }
                                })
                              }}
                            />
                            <span>{labelText}</span>
                          </label>
                        )
                      })}
                    </div>
                  ) : null}
                  {!clubDirectory.length && showModal ? (
                    <p style={{ margin: '10px 0 0', fontSize: '0.82rem', color: 'var(--text3)', lineHeight: 1.4 }}>
                      Keine Einträge im Vereins-Mitgliederverzeichnis oder noch nicht geladen (nur für Vereinsinterne).
                    </p>
                  ) : null}
                </div>

                <TrainingPlanExerciseVisibilityPanel
                  sections={formData.sections}
                  targetClubId={planningModalClubId}
                  user={user}
                  onMetaRefresh={refreshPlanningSectionMeta}
                />

                <div style={{ marginTop: '2rem' }}>
                {editingUnit ? (
                  <div style={{ marginBottom: '1rem' }}>
                    <div
                      role="radiogroup"
                      aria-label="Modus für Abschnitte und Übungen"
                      style={{
                        display: 'flex',
                        flexWrap: 'wrap',
                        alignItems: 'center',
                        gap: '10px',
                      }}
                    >
                      <span className="form-label" style={{ marginBottom: 0, fontSize: '0.82rem' }}>
                        Ablauf bearbeiten als
                      </span>
                      <div
                        style={{
                          display: 'inline-flex',
                          borderRadius: '10px',
                          border: '1.5px solid var(--border2)',
                          overflow: 'hidden',
                          background: 'var(--surface2)',
                        }}
                      >
                        {[
                          { id: 'planning', label: 'Planung' },
                          { id: 'debrief', label: 'Nachbereitung' },
                        ].map((opt, i) => (
                          <button
                            key={opt.id}
                            type="button"
                            role="radio"
                            aria-checked={sectionsEditMode === opt.id}
                            onClick={() => setSectionsEditMode(opt.id)}
                            style={{
                              border: 'none',
                              padding: '8px 14px',
                              fontWeight: 600,
                              fontSize: '0.85rem',
                              cursor: 'pointer',
                              background: sectionsEditMode === opt.id ? 'var(--accent-dark)' : 'transparent',
                              color: sectionsEditMode === opt.id ? '#fff' : 'var(--text1)',
                              whiteSpace: 'nowrap',
                              ...(i > 0 ? { borderLeft: '1.5px solid var(--border2)' } : {}),
                            }}
                          >
                            {opt.label}
                          </button>
                        ))}
                      </div>
                    </div>
                    <p style={{ margin: '0.35rem 0 0', fontSize: '0.82rem', color: 'var(--text3)', lineHeight: 1.45 }}>
                      {sectionsEditMode === 'debrief'
                        ? 'Ist‑Minuten rechts in derselben Spaltenbreite wie „Min“ (Plan); Abweichungen als Text über die volle Breite.'
                        : 'Ablauf, Übungen und geplante Minuten. Ist‑Werte und Abweichungen unter „Nachbereitung“.'}
                    </p>
                  </div>
                ) : null}
                <TrainingUnitSectionsEditor
                  heading="Abschnitte & Übungen"
                  headingAccessory={
                    <>
                      <button type="button" className="btn btn-secondary" onClick={handleSaveAsTemplate}>
                        Vorlage aus Aufbau speichern
                      </button>
                    </>
                  }
                  sections={formData.sections}
                  wideExerciseGrid
                  onSectionsChange={(updater) =>
                    setFormData((prev) => ({
                      ...prev,
                      sections: updater(prev.sections),
                    }))
                  }
                  onRequestTrainingModulePick={(ctx) => {
                    void openModuleApplyModal(ctx)
                  }}
                  onRequestExercisePick={({ sectionIndex, itemIndex, insertBeforeIndex }) => {
                    setExercisePickerTarget({
                      sIdx: sectionIndex,
                      iIdx: typeof itemIndex === 'number' ? itemIndex : undefined,
                      insertBeforeIndex:
                        typeof insertBeforeIndex === 'number' && Number.isFinite(insertBeforeIndex)
                          ? insertBeforeIndex
                          : undefined,
                    })
                    setExercisePickerOpen(true)
                  }}
                  onPeekExercise={(id, variantId, peekExtras) =>
                    setPlanningPeekCtx({
                      exerciseId: id,
                      variantId: variantId ?? null,
                      peekExtras: peekExtras ?? null,
                    })
                  }
                  showExecutionExtras={Boolean(editingUnit) && sectionsEditMode === 'debrief'}
                />
                </div>

                <div style={{ marginBottom: '1.75rem' }} />

                {editingUnit && (
                  <>
                    <h3 style={{ marginTop: '0.5rem', marginBottom: '1rem' }}>Durchführung</h3>

                    <div className="responsive-grid-4" style={{ marginBottom: '1rem' }}>
                      <div className="form-row">
                        <label className="form-label">Tatsächliches Datum</label>
                        <input
                          type="date"
                          className="form-input"
                          value={formData.actual_date}
                          onChange={(e) => updateFormField('actual_date', e.target.value)}
                        />
                      </div>

                      <div className="form-row">
                        <label className="form-label">Von</label>
                        <input
                          type="time"
                          className="form-input"
                          value={formData.actual_time_start}
                          onChange={(e) => updateFormField('actual_time_start', e.target.value)}
                        />
                      </div>

                      <div className="form-row">
                        <label className="form-label">Bis</label>
                        <input
                          type="time"
                          className="form-input"
                          value={formData.actual_time_end}
                          onChange={(e) => updateFormField('actual_time_end', e.target.value)}
                        />
                      </div>

                      <div className="form-row">
                        <label className="form-label">Teilnehmer</label>
                        <input
                          type="number"
                          className="form-input"
                          value={formData.attendance_count}
                          onChange={(e) => updateFormField('attendance_count', e.target.value)}
                        />
                      </div>
                    </div>

                    <div className="form-row">
                      <label className="form-label">Status</label>
                      <select
                        className="form-input"
                        value={formData.status}
                        onChange={(e) => updateFormField('status', e.target.value)}
                      >
                        <option value="planned">Geplant</option>
                        <option value="completed">Durchgeführt</option>
                        <option value="cancelled">Abgesagt</option>
                      </select>
                    </div>

                    {formData.status === 'completed' ? (
                      <div className="form-row" style={{ marginTop: '0.75rem' }}>
                        <label
                          style={{
                            display: 'flex',
                            alignItems: 'flex-start',
                            gap: '10px',
                            cursor: 'pointer',
                            lineHeight: 1.45,
                          }}
                        >
                          <input
                            type="checkbox"
                            checked={!!formData.debrief_completed}
                            onChange={(e) => updateFormField('debrief_completed', e.target.checked)}
                            style={{ marginTop: '3px' }}
                          />
                          <span>
                            <strong>Rückschau erledigt</strong>
                            <span className="muted" style={{ display: 'block', fontSize: '0.82rem', marginTop: '5px' }}>
                              Wenn angehakt, erscheint die Einheit nicht mehr unter „Offene Rückschau“ auf dem
                              Dashboard (Nachbereitung gilt als abgeschlossen).
                            </span>
                          </span>
                        </label>
                      </div>
                    ) : null}
                  </>
                )}

                <h3 style={{ marginTop: '2rem', marginBottom: '1rem' }}>Notizen</h3>

                <div className="form-row">
                  <label className="form-label">Öffentliche Notizen</label>
                  <textarea
                    className="form-input"
                    rows={3}
                    value={formData.notes}
                    onChange={(e) => updateFormField('notes', e.target.value)}
                    placeholder="Für Teilnehmer"
                  />
                </div>

                <div className="form-row">
                  <label className="form-label">Trainernotizen</label>
                  <textarea
                    className="form-input"
                    rows={3}
                    value={formData.trainer_notes}
                    onChange={(e) => updateFormField('trainer_notes', e.target.value)}
                  />
                </div>

                <div style={{ display: 'flex', gap: '0.5rem', marginTop: '1.5rem' }}>
                  <button type="submit" className="btn btn-primary" style={{ flex: 1 }}>
                    {editingUnit ? 'Speichern' : 'Erstellen'}
                  </button>
                  <button type="button" className="btn btn-secondary" onClick={() => setShowModal(false)}>
                    Abbrechen
                  </button>
                </div>
              </form>
            </div>
          </div>
        )}
      <ExercisePickerModal
        open={exercisePickerOpen}
        multiSelect
        enableQuickCreateDraft
        onClose={() => {
          setExercisePickerOpen(false)
          setExercisePickerTarget(null)
        }}
        onSelectExercises={async (picked) => {
          if (!exercisePickerTarget || !picked?.length) return
          const rows = []
          for (const ex of picked) {
            const row = await hydrateExercisePlanningRow(ex)
            if (row) rows.push(row)
          }
          if (!rows.length) return
          const { sIdx, iIdx, insertBeforeIndex } = exercisePickerTarget
          setFormData((prev) => ({
            ...prev,
            sections: prev.sections.map((s, si) => {
              if (si !== sIdx) return s
              const items = [...(s.items || [])]
              if (typeof iIdx === 'number') {
                const cur = items[iIdx]
                if (!cur || cur.item_type !== 'exercise') return s
                const [first, ...tail] = rows
                items[iIdx] = {
                  ...cur,
                  exercise_id: first.exercise_id,
                  exercise_variant_id: first.exercise_variant_id,
                  exercise_title: first.exercise_title,
                  variants: first.variants,
                }
                if (tail.length) items.splice(iIdx + 1, 0, ...tail)
                return { ...s, items }
              }
              const rawAt =
                typeof insertBeforeIndex === 'number' && Number.isFinite(insertBeforeIndex)
                  ? insertBeforeIndex
                  : items.length
              const at = Math.max(0, Math.min(rawAt, items.length))
              items.splice(at, 0, ...rows)
              return { ...s, items }
            }),
          }))
          setExercisePickerOpen(false)
          setExercisePickerTarget(null)
        }}
      />
      <ExercisePeekModal
        open={planningPeekCtx != null}
        exerciseId={planningPeekCtx?.exerciseId}
        variantId={planningPeekCtx?.variantId ?? undefined}
        peekExtras={planningPeekCtx?.peekExtras ?? undefined}
        onClose={() => setPlanningPeekCtx(null)}
      />
    </div>
  )
}

export default TrainingPlanningPage
