import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { useLocation, useNavigate, useParams } from 'react-router-dom'
import api from '../utils/api'
import ExercisePickerModal from '../components/ExercisePickerModal'
import FormActionBar from '../components/FormActionBar'
import SkillProfilePanel from '../components/skills/SkillProfilePanel'
import { hydrateExercisePlanningRow } from '../utils/trainingUnitSectionsForm'
import { useAuth } from '../context/AuthContext'
import { useToast } from '../context/ToastContext'
import UnsavedChangesPrompt from '../components/UnsavedChangesPrompt'
import { useBeforeUnloadWhen, useUnsavedChangesBlocker } from '../hooks/useUnsavedChangesBlocker'
import { activeClubMemberships, getDefaultClubIdForGovernanceForms, getTenantClubDependencyKey } from '../utils/activeClub'
import {
  buildTrainingModulesListReturnContext,
  goNavReturn,
  preserveAppReturnOnNavigate,
} from '../utils/navReturnContext'

function moduleFormSnapshot({
  title,
  summary,
  goal,
  recommendedDurationMin,
  targetGroupNotes,
  deploymentContextNotes,
  visibility,
  clubIdField,
  primaryMethodId,
  items,
}) {
  const itemRows = items.map((it) => {
    if (it.item_type === 'note') {
      return { k: 'n', b: it.note_body ?? '' }
    }
    return {
      k: 'e',
      id: it.exercise_id,
      v: it.exercise_variant_id,
      d: it.planned_duration_min,
      n: it.notes ?? '',
    }
  })
  return JSON.stringify({
    title: (title || '').trim(),
    summary: (summary || '').trim(),
    goal: goal || '',
    recommendedDurationMin: recommendedDurationMin || '',
    targetGroupNotes: targetGroupNotes || '',
    deploymentContextNotes: deploymentContextNotes || '',
    visibility: visibility || '',
    clubIdField: (clubIdField || '').trim(),
    primaryMethodId: (primaryMethodId || '').trim(),
    items: itemRows,
  })
}

function nextLocalKey() {
  return `m-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`
}

function swapItems(arr, i, j) {
  if (i === j || i < 0 || j < 0 || i >= arr.length || j >= arr.length) return [...arr]
  const n = [...arr]
  ;[n[i], n[j]] = [n[j], n[i]]
  return n
}

export default function TrainingModuleEditPage() {
  const { id: routeId } = useParams()
  const navigate = useNavigate()
  const location = useLocation()
  const isNew = !routeId || routeId === 'new'
  const moduleId = !isNew ? parseInt(routeId, 10) : NaN

  const [loading, setLoading] = useState(!isNew)
  const [saving, setSaving] = useState(false)
  const [methods, setMethods] = useState([])
  const [pickerOpen, setPickerOpen] = useState(false)
  const [error, setError] = useState('')
  const [skillProfileData, setSkillProfileData] = useState(null)
  const [skillProfileLoading, setSkillProfileLoading] = useState(false)
  const [skillProfileError, setSkillProfileError] = useState('')
  const [skillProfileTick, setSkillProfileTick] = useState(0)

  const [title, setTitle] = useState('')
  const [summary, setSummary] = useState('')
  const [goal, setGoal] = useState('')
  const [recommendedDurationMin, setRecommendedDurationMin] = useState('')
  const [targetGroupNotes, setTargetGroupNotes] = useState('')
  const [deploymentContextNotes, setDeploymentContextNotes] = useState('')
  const [visibility, setVisibility] = useState('club')
  const [clubIdField, setClubIdField] = useState('')
  const [primaryMethodId, setPrimaryMethodId] = useState('')
  const [items, setItems] = useState([])

  const toast = useToast()
  const baselineRef = useRef(null)
  const latestFormRef = useRef({})
  const [baselineReady, setBaselineReady] = useState(false)
  const [bypassDirty, setBypassDirty] = useState(false)

  latestFormRef.current = {
    title,
    summary,
    goal,
    recommendedDurationMin,
    targetGroupNotes,
    deploymentContextNotes,
    visibility,
    clubIdField,
    primaryMethodId,
    items,
  }

  const dirtySignature = moduleFormSnapshot(latestFormRef.current)

  useEffect(() => {
    baselineRef.current = null
    setBaselineReady(false)
    setBypassDirty(false)
  }, [isNew, moduleId])

  useEffect(() => {
    if (loading) return
    const handle = window.setTimeout(() => {
      baselineRef.current = moduleFormSnapshot(latestFormRef.current)
      setBaselineReady(true)
    }, 120)
    return () => clearTimeout(handle)
  }, [loading, isNew, moduleId])

  const formDirtyEffective =
    baselineReady && baselineRef.current != null && !bypassDirty && !loading && dirtySignature !== baselineRef.current

  const blocker = useUnsavedChangesBlocker(Boolean(formDirtyEffective && !saving))
  useBeforeUnloadWhen(Boolean(formDirtyEffective && !saving))

  useEffect(() => {
    if (isNew || !Number.isFinite(moduleId)) {
      setSkillProfileData(null)
      return undefined
    }
    let cancelled = false
    ;(async () => {
      setSkillProfileLoading(true)
      setSkillProfileError('')
      try {
        const data = await api.getTrainingModuleSkillProfile(moduleId)
        if (!cancelled) setSkillProfileData(data)
      } catch (e) {
        if (!cancelled) {
          setSkillProfileData(null)
          setSkillProfileError(e.message || 'Fähigkeiten-Profil nicht geladen')
        }
      } finally {
        if (!cancelled) setSkillProfileLoading(false)
      }
    })()
    return () => {
      cancelled = true
    }
  }, [isNew, moduleId, skillProfileTick])

  const { user } = useAuth()
  const isPlatformAdmin = user?.role === 'admin' || user?.role === 'superadmin'
  const tenantClubDepKey = useMemo(() => getTenantClubDependencyKey(user), [user])
  const [clubsForGovernanceForms, setClubsForGovernanceForms] = useState([])

  useEffect(() => {
    if (!isPlatformAdmin) {
      setClubsForGovernanceForms([])
      return undefined
    }
    let cancelled = false
    ;(async () => {
      try {
        const list = await api.listClubs()
        if (!cancelled) setClubsForGovernanceForms(Array.isArray(list) ? list : [])
      } catch {
        if (!cancelled) setClubsForGovernanceForms([])
      }
    })()
    return () => {
      cancelled = true
    }
  }, [isPlatformAdmin, tenantClubDepKey])

  const membershipClubRows = useMemo(() => activeClubMemberships(user?.clubs ?? []), [user?.clubs])

  const visibilityClubChoices = useMemo(() => {
    if (isPlatformAdmin && clubsForGovernanceForms.length > 0) {
      return [...clubsForGovernanceForms].sort((a, b) =>
        String(a.name || '').localeCompare(String(b.name || ''), 'de'),
      )
    }
    return [...membershipClubRows].sort((a, b) =>
      String(a.name || '').localeCompare(String(b.name || ''), 'de'),
    )
  }, [isPlatformAdmin, clubsForGovernanceForms, membershipClubRows])

  useEffect(() => {
    if (!isNew || visibility !== 'club') return
    if ((clubIdField || '').trim() !== '') return
    const xs = visibilityClubChoices
    if (xs.length === 1) setClubIdField(String(xs[0].id))
    else {
      const r = getDefaultClubIdForGovernanceForms(user)
      if (r != null && xs.some((c) => Number(c.id) === Number(r))) setClubIdField(String(r))
    }
  }, [isNew, visibility, clubIdField, visibilityClubChoices, user])

  const itemsPayload = items.map((it, i) => {
    if (it.item_type === 'note') {
      return { item_type: 'note', order_index: i, note_body: it.note_body ?? '' }
    }
    const vid =
      it.exercise_variant_id !== '' && it.exercise_variant_id != null
        ? parseInt(it.exercise_variant_id, 10)
        : null
    return {
      item_type: 'exercise',
      order_index: i,
      exercise_id: parseInt(it.exercise_id, 10),
      exercise_variant_id: Number.isFinite(vid) ? vid : null,
      planned_duration_min:
        it.planned_duration_min !== '' && it.planned_duration_min != null
          ? parseInt(String(it.planned_duration_min), 10)
          : null,
      notes: it.notes?.trim() ? it.notes.trim() : null,
    }
  })

  const loadCatalogs = useCallback(async () => {
    try {
      const m = await api.listMethods({})
      setMethods(Array.isArray(m) ? m : [])
    } catch {
      setMethods([])
    }
  }, [])

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

  useEffect(() => {
    if (isNew || !Number.isFinite(moduleId)) {
      setLoading(false)
      return
    }
    let cancelled = false
    async function load() {
      setLoading(true)
      setError('')
      try {
        const m = await api.getTrainingModule(moduleId)
        if (cancelled) return
        setTitle((m.title || '').trim())
        setSummary((m.summary || '').trim())
        setGoal(m.goal || '')
        setRecommendedDurationMin(
          m.recommended_duration_min != null && m.recommended_duration_min !== ''
            ? String(m.recommended_duration_min)
            : ''
        )
        setTargetGroupNotes(m.target_group_notes || '')
        setDeploymentContextNotes(m.deployment_context_notes || '')
        setVisibility((m.visibility || 'club').trim())
        setClubIdField(m.club_id != null ? String(m.club_id) : '')
        setPrimaryMethodId(m.primary_method_id != null ? String(m.primary_method_id) : '')
        const nextItems = []
        for (const row of Array.isArray(m.items) ? m.items : []) {
          if (row.item_type === 'note') {
            nextItems.push({ localKey: nextLocalKey(), item_type: 'note', note_body: row.note_body || '' })
            continue
          }
          const ex = await hydrateExercisePlanningRow({
            id: row.exercise_id,
            title: '',
            variants: [],
          })
          if (ex) {
            ex.localKey = nextLocalKey()
            if (row.exercise_variant_id) ex.exercise_variant_id = String(row.exercise_variant_id)
            ex.planned_duration_min =
              row.planned_duration_min != null && row.planned_duration_min !== ''
                ? String(row.planned_duration_min)
                : ''
            ex.notes = row.notes || ''
            nextItems.push(ex)
          }
        }
        setItems(nextItems)
      } catch (e) {
        if (!cancelled) setError(e.message || 'Laden fehlgeschlagen')
      } finally {
        if (!cancelled) setLoading(false)
      }
    }
    load()
    return () => {
      cancelled = true
    }
  }, [isNew, moduleId])

  const buildBody = () => {
    let cid = null
    if (visibility === 'club') {
      const raw = (clubIdField || '').trim()
      if (raw !== '') {
        const p = parseInt(raw, 10)
        if (Number.isFinite(p) && p >= 1) cid = p
      } else if (visibilityClubChoices.length === 1) {
        cid = visibilityClubChoices[0].id
      }
    }
    const pm =
      primaryMethodId !== '' && primaryMethodId != null ? parseInt(primaryMethodId, 10) : null
    return {
      title: title.trim(),
      summary: summary.trim() || null,
      goal: goal.trim() || null,
      recommended_duration_min:
        recommendedDurationMin !== '' ? parseInt(recommendedDurationMin, 10) : null,
      target_group_notes: targetGroupNotes.trim() || null,
      deployment_context_notes: deploymentContextNotes.trim() || null,
      visibility,
      club_id:
        cid != null && Number.isFinite(cid) && cid >= 1
          ? cid
          : visibility === 'club'
            ? undefined
            : null,
      primary_method_id:
        pm != null && Number.isFinite(pm) && pm >= 1 ? pm : null,
      items: itemsPayload.filter((row) =>
        row.item_type === 'note' ? true : Number.isFinite(row.exercise_id) && row.exercise_id >= 1
      ),
    }
  }

  const moduleListReturn = useMemo(() => buildTrainingModulesListReturnContext(), [])

  const goBack = useCallback(() => {
    goNavReturn(navigate, location, moduleListReturn)
  }, [navigate, location, moduleListReturn])

  const performModuleSave = async ({ fromUnsavedDialog = false, closeAfter = false } = {}) => {
    if (!title.trim()) {
      toast.error('Titel ist Pflicht.')
      return false
    }
    setSaving(true)
    setError('')
    try {
      const body = buildBody()
      if (isNew) {
        const created = await api.createTrainingModule(body)
        toast.success('Trainingsmodul angelegt.')
        if (closeAfter) {
          goBack()
        } else if (!fromUnsavedDialog) {
          preserveAppReturnOnNavigate(navigate, location, `/planning/training-modules/${created.id}`, {
            replace: true,
          })
        }
        return true
      }
      await api.updateTrainingModule(moduleId, body)
      baselineRef.current = moduleFormSnapshot(latestFormRef.current)
      setBypassDirty(false)
      toast.success('Gespeichert.')
      setSkillProfileTick((t) => t + 1)
      if (closeAfter) goBack()
      return true
    } catch (err) {
      const msg = err.message || 'Speichern fehlgeschlagen'
      setError(msg)
      toast.error(msg)
      return false
    } finally {
      setSaving(false)
    }
  }

  const handleSave = async (e) => {
    e?.preventDefault?.()
    await performModuleSave({ fromUnsavedDialog: false, closeAfter: false })
  }

  const handleSaveAndClose = async () => {
    await performModuleSave({ fromUnsavedDialog: false, closeAfter: true })
  }

  const handleUnsavedDialogSave = async () => {
    const ok = await performModuleSave({ fromUnsavedDialog: true })
    if (ok) blocker.proceed()
  }

  const pickExercise = async (ex) => {
    if (!ex?.id) return
    const row = await hydrateExercisePlanningRow(ex)
    if (row) row.localKey = nextLocalKey()
    if (row) setItems((prev) => [...prev, row])
    setPickerOpen(false)
  }

  return (
    <div className="app-page">
      <h1 className="page-title">{isNew ? 'Neues Trainingsmodul' : 'Trainingsmodul bearbeiten'}</h1>
      <p style={{ color: 'var(--text2)', fontSize: '0.95rem', marginBottom: '1.25rem', maxWidth: '40rem' }}>
        Reihenfolge der Positionen entspricht der späteren Übernahme in einen Abschnitt der Einheit (Kopie).
      </p>

      {error ? <p style={{ color: 'var(--danger)', marginBottom: '1rem' }}>{error}</p> : null}
      {loading ? (
        <p style={{ color: 'var(--text2)' }}>Laden …</p>
      ) : (
        <form
          id="training-module-form"
          className="card page-form-shell"
          style={{ padding: 'clamp(14px, 3vw, 1.75rem)', maxWidth: '720px' }}
          onSubmit={handleSave}
        >
          <div className="page-form-shell__scroll">
          {!isNew ? (
            <SkillProfilePanel
              title="Fähigkeiten im Modul"
              profile={skillProfileData?.overall}
              loading={skillProfileLoading}
              error={skillProfileError}
              artifactType="training_module"
            />
          ) : null}
          <div className="form-row">
            <label className="form-label">Titel *</label>
            <input className="form-input" value={title} onChange={(e) => setTitle(e.target.value)} />
          </div>
          <div className="form-row">
            <label className="form-label">Kurzbeschreibung</label>
            <textarea className="form-input" rows={2} value={summary} onChange={(e) => setSummary(e.target.value)} />
          </div>
          <div className="form-row">
            <label className="form-label">Ziel</label>
            <textarea className="form-input" rows={3} value={goal} onChange={(e) => setGoal(e.target.value)} />
          </div>
          <div className="form-row" style={{ display: 'grid', gap: '1rem', gridTemplateColumns: '1fr 1fr' }}>
            <div>
              <label className="form-label">Empfohlene Dauer (Min.)</label>
              <input
                className="form-input"
                type="number"
                min={0}
                value={recommendedDurationMin}
                onChange={(e) => setRecommendedDurationMin(e.target.value)}
              />
            </div>
            <div>
              <label className="form-label">Primäre Trainingsmethode</label>
              <select
                className="form-input"
                value={primaryMethodId}
                onChange={(e) => setPrimaryMethodId(e.target.value)}
              >
                <option value="">—</option>
                {methods.map((m) => (
                  <option key={m.id} value={String(m.id)}>
                    {(m.name || '').trim() || `Methode #${m.id}`}
                  </option>
                ))}
              </select>
            </div>
          </div>
          <div className="form-row">
            <label className="form-label">Empfohlene Zielgruppe (Freitext)</label>
            <textarea
              className="form-input"
              rows={2}
              value={targetGroupNotes}
              onChange={(e) => setTargetGroupNotes(e.target.value)}
            />
          </div>
          <div className="form-row">
            <label className="form-label">Einsatz / Kontext</label>
            <textarea
              className="form-input"
              rows={2}
              value={deploymentContextNotes}
              onChange={(e) => setDeploymentContextNotes(e.target.value)}
            />
          </div>

          <div className="form-row" style={{ display: 'grid', gap: '1rem', gridTemplateColumns: '1fr 1fr' }}>
            <div>
              <label className="form-label">Sichtbarkeit</label>
              <select
                className="form-input"
                value={visibility}
                onChange={(e) => {
                  const v = e.target.value
                  setVisibility(v)
                  if (v !== 'club') {
                    setClubIdField('')
                    return
                  }
                  const xs = visibilityClubChoices
                  if (xs.length === 1) setClubIdField(String(xs[0].id))
                  else if (xs.length === 0) setClubIdField('')
                  else {
                    const resolved = getDefaultClubIdForGovernanceForms(user)
                    setClubIdField(
                      resolved != null && xs.some((c) => Number(c.id) === Number(resolved))
                        ? String(resolved)
                        : '',
                    )
                  }
                }}
              >
                <option value="private">Privat</option>
                <option value="club">Vereinsintern</option>
                <option value="official">Offiziell</option>
              </select>
            </div>
            <div>
              <label className="form-label">Verein (bei „Vereinsintern“)</label>
              {visibility !== 'club' ? (
                <p style={{ margin: '0.25rem 0 0', fontSize: '0.85rem', color: 'var(--text3)', lineHeight: 1.45 }}>
                  Bei privaten oder offiziellen Modulen ist keine Vereinszuordnung nötig (Server legt keine
                  Vereinsbindung fest).
                </p>
              ) : visibilityClubChoices.length === 0 ? (
                <p style={{ margin: '0.25rem 0 0', fontSize: '0.85rem', color: 'var(--danger)', lineHeight: 1.45 }}>
                  Kein Verein zur Auswahl — bitte aktiven Verein im Profil wählen oder (Plattform-Admin) Vereinsliste
                  laden.
                </p>
              ) : visibilityClubChoices.length === 1 ? (
                <>
                  <input
                    className="form-input"
                    disabled
                    readOnly
                    value={
                      (visibilityClubChoices[0].short_name || visibilityClubChoices[0].name || '').trim() ||
                      `Verein #${visibilityClubChoices[0].id}`
                    }
                  />
                  <p style={{ margin: '0.35rem 0 0', fontSize: '0.82rem', color: 'var(--text3)', lineHeight: 1.45 }}>
                    Fixiert durch deine Mitgliedschaft. Verein-ID {visibilityClubChoices[0].id} wird beim Speichern
                    verwendet.
                  </p>
                </>
              ) : (
                <>
                  <select
                    className="form-input"
                    value={clubIdField}
                    onChange={(e) => setClubIdField(e.target.value)}
                  >
                    <option value="">Automatisch (aktueller Verein im Profil)</option>
                    {visibilityClubChoices.map((c) => {
                      const ln = `${((c.short_name || c.name || '').trim() || '') || `Verein #${c.id}`}`
                      return (
                        <option key={c.id} value={String(c.id)}>
                          {ln}
                        </option>
                      )
                    })}
                  </select>
                  <p style={{ margin: '0.35rem 0 0', fontSize: '0.82rem', color: 'var(--text3)', lineHeight: 1.45 }}>
                    Bei „Automatisch“ entscheidet der aktiv gewählte Verein beim Speichern (wie bei anderen
                    Bibliotheksinhalten).
                  </p>
                </>
              )}
            </div>
          </div>

          <hr style={{ border: 'none', borderTop: '1px solid var(--border)', margin: '1.25rem 0' }} />

          <h3 style={{ fontSize: '1rem', marginBottom: '0.75rem' }}>Positionen</h3>
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px', marginBottom: '12px' }}>
            <button type="button" className="btn btn-secondary" onClick={() => setPickerOpen(true)}>
              Übung hinzufügen
            </button>
            <button
              type="button"
              className="btn btn-secondary"
              onClick={() =>
                setItems((prev) => [...prev, { localKey: nextLocalKey(), item_type: 'note', note_body: '' }])
              }
            >
              Notiz hinzufügen
            </button>
          </div>

          <ul style={{ listStyle: 'none', padding: 0, margin: 0, display: 'flex', flexDirection: 'column', gap: '10px' }}>
            {items.map((it, idx) => (
              <li key={it.localKey || idx} style={{ padding: '10px', background: 'var(--surface2)', borderRadius: '8px' }}>
                {it.item_type === 'note' ? (
                  <div>
                    <span style={{ fontWeight: 600, fontSize: '0.85rem', color: 'var(--text3)' }}>Notiz</span>
                    <textarea
                      className="form-input"
                      style={{ marginTop: '8px' }}
                      rows={2}
                      value={it.note_body}
                      onChange={(e) => {
                        const v = e.target.value
                        setItems((prev) =>
                          prev.map((x, j) =>
                            j === idx && x.item_type === 'note' ? { ...x, note_body: v } : x
                          )
                        )
                      }}
                    />
                  </div>
                ) : (
                  <>
                    <div style={{ fontWeight: 700, wordBreak: 'break-word', marginBottom: '8px' }}>
                      {(it.exercise_title || '').trim() || `Übung #${it.exercise_id}`}
                    </div>
                    <div style={{ display: 'grid', gap: '8px', gridTemplateColumns: '1fr 1fr' }}>
                      <div>
                        <label className="form-label" style={{ fontSize: '0.78rem' }}>
                          Variante
                        </label>
                        <select
                          className="form-input"
                          value={String(it.exercise_variant_id ?? '')}
                          onChange={(e) => {
                            const v = e.target.value
                            setItems((prev) =>
                              prev.map((row, j) =>
                                j === idx && row.item_type === 'exercise' ? { ...row, exercise_variant_id: v } : row
                              )
                            )
                          }}
                        >
                          <option value="">—</option>
                          {(it.variants || []).map((v) => (
                            <option key={v.id} value={String(v.id)}>
                              {(v.name || '').trim() || `Variante #${v.id}`}
                            </option>
                          ))}
                        </select>
                      </div>
                      <div>
                        <label className="form-label" style={{ fontSize: '0.78rem' }}>
                          Minuten (plan)
                        </label>
                        <input
                          className="form-input"
                          type="number"
                          min={0}
                          value={it.planned_duration_min}
                          onChange={(e) =>
                            setItems((prev) =>
                              prev.map((row, j) =>
                                j === idx && row.item_type === 'exercise'
                                  ? { ...row, planned_duration_min: e.target.value }
                                  : row
                              )
                            )
                          }
                        />
                      </div>
                    </div>
                    <div style={{ marginTop: '8px' }}>
                      <label className="form-label" style={{ fontSize: '0.78rem' }}>
                        Hinweis zur Position
                      </label>
                      <input
                        className="form-input"
                        value={it.notes ?? ''}
                        onChange={(e) =>
                          setItems((prev) =>
                            prev.map((row, j) =>
                              j === idx && row.item_type === 'exercise' ? { ...row, notes: e.target.value } : row
                            )
                          )
                        }
                      />
                    </div>
                  </>
                )}
                <div style={{ display: 'flex', gap: '8px', marginTop: '10px', flexWrap: 'wrap' }}>
                  <button
                    type="button"
                    className="btn btn-secondary"
                    disabled={idx < 1}
                    onClick={() => setItems((prev) => swapItems(prev, idx, idx - 1))}
                  >
                    Nach oben
                  </button>
                  <button
                    type="button"
                    className="btn btn-secondary"
                    disabled={idx >= items.length - 1}
                    onClick={() => setItems((prev) => swapItems(prev, idx, idx + 1))}
                  >
                    Nach unten
                  </button>
                  <button
                    type="button"
                    className="btn btn-secondary"
                    onClick={() => setItems((prev) => prev.filter((_, j) => j !== idx))}
                  >
                    Entfernen
                  </button>
                </div>
              </li>
            ))}
          </ul>

          </div>

          <FormActionBar
            formId="training-module-form"
            isNew={isNew}
            saving={saving}
            onSave={() => handleSave()}
            onSaveAndClose={handleSaveAndClose}
            onCancel={goBack}
            cancelLabel="Abbrechen"
          />
        </form>
      )}

      <ExercisePickerModal open={pickerOpen} onClose={() => setPickerOpen(false)} onSelectExercise={pickExercise} />
      <UnsavedChangesPrompt
        blocker={blocker}
        isBusy={saving}
        onSave={handleUnsavedDialogSave}
        onDiscardWithoutSave={() => setBypassDirty(true)}
      />
    </div>
  )
}
