/**
 * Planungs-KI Phase C3/E3: Ziel → Übungspfad vorschlagen → Lücken mit KI anlegen → in Graph speichern.
 */
import React, { useCallback, useEffect, useState } from 'react'
import api from '../utils/api'
import ExerciseAiQuickCreateModal from './exercises/ExerciseAiQuickCreateModal'
import ExerciseAiSuggestPreviewModal from './ExerciseAiSuggestPreviewModal'
import {
  aiPreviewToQuickCreateDraft,
  buildQuickCreateAiPreview,
  buildQuickCreateExercisePayloadFromDraft,
} from '../utils/exerciseAiQuickCreate'
import {
  buildPathGapPlanningContextForAi,
  gapOfferContextDisplayLines,
} from '../utils/planningContextForExerciseAi'

function applyResolvedStructuredFromRoadmap(progressionRoadmap, setters) {
  const rs = progressionRoadmap?.resolved_structured
  if (!rs) return
  if (rs.start_situation) setters.setStartSituation(String(rs.start_situation))
  if (rs.target_state) setters.setTargetState(String(rs.target_state))
  if (rs.roadmap_notes) setters.setRoadmapNotes(String(rs.roadmap_notes))
}

function GapOfferContextPreview({ lines }) {
  if (!Array.isArray(lines) || lines.length === 0) return null
  return (
    <details
      style={{
        marginTop: '8px',
        fontSize: '12px',
        color: 'var(--text2)',
        borderTop: '1px dashed var(--border)',
        paddingTop: '8px',
      }}
    >
      <summary style={{ cursor: 'pointer', color: 'var(--accent-dark)', fontWeight: 600 }}>
        KI-Kontext für diese Übung ({lines.length} Punkte)
      </summary>
      <dl style={{ margin: '8px 0 0', display: 'grid', gap: '6px' }}>
        {lines.map(({ label, value }) => (
          <div key={label}>
            <dt style={{ margin: 0, fontSize: '11px', color: 'var(--text3)' }}>{label}</dt>
            <dd style={{ margin: '2px 0 0', lineHeight: 1.45 }}>{value}</dd>
          </div>
        ))}
      </dl>
      <p style={{ margin: '8px 0 0', fontSize: '11px', color: 'var(--text3)', lineHeight: 1.4 }}>
        Dieser Kontext wird an die Übungs-KI übergeben (Ziel, Fähigkeiten, Anleitung) — nicht nur das
        Stufen-Lernziel oben.
      </p>
    </details>
  )
}

function sourceLabel(source) {
  const map = {
    user: 'manuell',
    llm: 'KI-Extraktion',
    regex: 'Muster (von … bis …)',
    merged: 'manuell + KI',
    heuristic: 'heuristisch',
    none: '—',
  }
  return map[source] || source || '—'
}

function roadmapStructuredPayload(startSituation, targetState, roadmapNotes) {
  const start = (startSituation || '').trim()
  const target = (targetState || '').trim()
  const notes = (roadmapNotes || '').trim()
  const body = {}
  if (start) body.start_situation = start
  if (target) body.target_state = target
  if (notes) body.roadmap_notes = notes
  return body
}

function emptyPathStep() {
  return { exerciseId: null, exerciseTitle: '', variantId: null, variants: [], reasons: [] }
}

function mapApiStepToRow(step) {
  const variants = Array.isArray(step?.variants) ? step.variants : []
  const rawVid = step?.variant_id ?? step?.suggested_variant_id ?? null
  const variantId =
    rawVid != null && Number.isFinite(Number(rawVid)) && Number(rawVid) > 0 ? Number(rawVid) : null
  const isAiProposal = Boolean(step?.is_ai_proposal) || step?.exercise_id == null
  return {
    exerciseId: step?.exercise_id != null ? Number(step.exercise_id) : null,
    proposalKey: step?.proposal_key || null,
    exerciseTitle:
      (step?.title || '').trim() ||
      (step?.exercise_id ? `Übung #${step.exercise_id}` : 'KI-Vorschlag'),
    variantId: isAiProposal ? null : variantId,
    variants: isAiProposal ? [] : variants,
    reasons: Array.isArray(step?.reasons) ? step.reasons : [],
    isBridge: Boolean(step?.is_bridge),
    isAiProposal,
    aiSuggestion: step?.ai_suggestion || null,
    semanticScore: step?.semantic_score,
    isOffTopic: false,
    roadmapMajorStepIndex:
      step?.roadmap_major_step_index != null ? Number(step.roadmap_major_step_index) : null,
    roadmapPhase: step?.roadmap_phase || null,
    roadmapLearningGoal: step?.roadmap_learning_goal || null,
  }
}

function mapCreatedExerciseToRow(ex, offer) {
  return {
    exerciseId: Number(ex.id),
    proposalKey: null,
    exerciseTitle: (ex.title || offer?.title_hint || '').trim() || `Übung #${ex.id}`,
    variantId: null,
    variants: [],
    reasons: ['Neu angelegt zur Schließung einer Pfad-Lücke'],
    isBridge: true,
    isAiProposal: false,
    aiSuggestion: null,
    semanticScore: null,
    isOffTopic: false,
  }
}

const OFFER_SOURCE_LABELS = {
  unfilled_gap: 'Lücke',
  off_topic: 'Themenfremd',
  llm_suggested: 'QS-Empfehlung',
  roadmap_unfilled: 'Roadmap-Stufe',
}

const PATH_STEPS_HARD_MAX = 10

const ROADMAP_PHASES = ['einstieg', 'grundlage', 'vertiefung', 'anwendung', 'perfektion']

function mapMajorStepsFromApi(apiRoadmap) {
  const raw = apiRoadmap?.roadmap?.major_steps
  if (!Array.isArray(raw)) return []
  return raw.map((s, i) => ({
    index: i,
    phase: s.phase || 'vertiefung',
    learning_goal: (s.learning_goal || '').trim(),
    consolidates: Array.isArray(s.consolidates) ? s.consolidates : [],
    rationale: s.rationale || '',
  }))
}

function reindexMajorSteps(rows) {
  return rows.map((row, i) => ({ ...row, index: i }))
}

function majorStepsToOverridePayload(rows) {
  return {
    major_steps: reindexMajorSteps(rows).map((row) => ({
      index: row.index,
      phase: row.phase || 'vertiefung',
      learning_goal: row.learning_goal.trim(),
      consolidates: row.consolidates || [],
      rationale: row.rationale || '',
    })),
  }
}

/** Einfügen wächst den Pfad; Ersetzen (replace_step_index) nicht. */
function offerGrowsPath(offer) {
  const replaceIdx = offer?.replace_step_index
  return !(replaceIdx != null && Number.isFinite(Number(replaceIdx)))
}

function isGapOfferBlockedByPathCapacity(offer, pathLen, maxSteps) {
  return offerGrowsPath(offer) && pathLen >= maxSteps
}

function neededMaxStepsAfterInsert(pathLen) {
  return Math.min(PATH_STEPS_HARD_MAX, pathLen + 1)
}

/**
 * Pfad voll, aber Einfügen gewünscht → Nutzer fragen, ob maxSteps dynamisch wächst.
 * @returns {boolean} true = fortfahren (ggf. maxSteps erhöht), false = abgebrochen
 */
function confirmPathExpansionIfNeeded(offer, pathLen, maxSteps, setMaxSteps) {
  if (!isGapOfferBlockedByPathCapacity(offer, pathLen, maxSteps)) {
    return true
  }
  if (maxSteps >= PATH_STEPS_HARD_MAX) {
    alert(
      `Maximale Pfadlänge (${PATH_STEPS_HARD_MAX} Schritte) erreicht. Bitte zuerst einen Schritt entfernen.`,
    )
    return false
  }
  const newMax = neededMaxStepsAfterInsert(pathLen)
  const titleHint = (offer?.title_hint || 'diese Übung').trim()
  const ok = window.confirm(
    `Maximale Pfadlänge (${maxSteps}) ist erreicht.\n\n` +
      `Soll die Pfadlänge auf ${newMax} Schritte vergrößert werden, um „${titleHint}“ einzufügen?\n\n` +
      'Es wird kein neuer Pfad-Vorschlag generiert.',
  )
  if (!ok) return false
  setMaxSteps(newMax)
  return true
}

function resolveDefaultFocusAreaId(targetSummary, focusAreas) {
  const targetName = targetSummary?.focus_areas?.[0]
  if (targetName && Array.isArray(focusAreas) && focusAreas.length) {
    const norm = String(targetName).trim().toLowerCase()
    const hit = focusAreas.find((fa) => String(fa.name || '').trim().toLowerCase() === norm)
    if (hit?.id) return Number(hit.id)
  }
  return focusAreas?.[0]?.id ? Number(focusAreas[0].id) : null
}

export default function ExerciseProgressionPathBuilder({
  graphId,
  disabled = false,
  onSaved,
}) {
  const [goalQuery, setGoalQuery] = useState('')
  const [startSituation, setStartSituation] = useState('')
  const [targetState, setTargetState] = useState('')
  const [roadmapNotes, setRoadmapNotes] = useState('')
  const [maxSteps, setMaxSteps] = useState(5)
  const [segmentNotes, setSegmentNotes] = useState('')
  const [saving, setSaving] = useState(false)
  const [error, setError] = useState('')
  const [targetSummary, setTargetSummary] = useState(null)
  const [semanticBrief, setSemanticBrief] = useState(null)
  const [pathQa, setPathQa] = useState(null)
  const [pathSteps, setPathSteps] = useState([])
  const [gapFillOffers, setGapFillOffers] = useState([])
  const [progressionRoadmap, setProgressionRoadmap] = useState(null)
  const [editableMajorSteps, setEditableMajorSteps] = useState([])
  const [roadmapDirty, setRoadmapDirty] = useState(false)
  const [loadingRoadmap, setLoadingRoadmap] = useState(false)
  const [loadingStartTarget, setLoadingStartTarget] = useState(false)
  const [loadingMatch, setLoadingMatch] = useState(false)
  const [startTargetAnalyzed, setStartTargetAnalyzed] = useState(false)
  const loading = loadingRoadmap || loadingStartTarget || loadingMatch
  const [focusAreas, setFocusAreas] = useState([])
  const [skillsCatalog, setSkillsCatalog] = useState([])
  const [generatingOfferId, setGeneratingOfferId] = useState(null)

  const [quickCreateOpen, setQuickCreateOpen] = useState(false)
  const [activeOffer, setActiveOffer] = useState(null)
  const [quickTitle, setQuickTitle] = useState('')
  const [quickSketch, setQuickSketch] = useState('')
  const [quickFocusAreaId, setQuickFocusAreaId] = useState('')
  const [quickCreateDraft, setQuickCreateDraft] = useState(null)
  const [quickSaving, setQuickSaving] = useState(false)
  const [quickAiError, setQuickAiError] = useState('')
  const [activePlanningContextLines, setActivePlanningContextLines] = useState([])

  useEffect(() => {
    let cancelled = false
    Promise.all([
      api.listFocusAreas({ status: 'active' }),
      api.listSkillsCatalog({ status: 'active' }),
    ])
      .then(([fa, sk]) => {
        if (cancelled) return
        setFocusAreas(Array.isArray(fa) ? fa : [])
        setSkillsCatalog(Array.isArray(sk) ? sk : [])
      })
      .catch(() => {
        if (!cancelled) {
          setFocusAreas([])
          setSkillsCatalog([])
        }
      })
    return () => {
      cancelled = true
    }
  }, [])

  const patchStep = useCallback((idx, patch) => {
    setPathSteps((prev) => prev.map((row, i) => (i === idx ? { ...row, ...patch } : row)))
  }, [])

  const removeStep = useCallback((idx) => {
    setPathSteps((prev) => (prev.length <= 2 ? prev : prev.filter((_, i) => i !== idx)))
  }, [])

  const patchMajorStep = useCallback((idx, patch) => {
    setEditableMajorSteps((prev) =>
      reindexMajorSteps(prev.map((row, i) => (i === idx ? { ...row, ...patch } : row))),
    )
    setRoadmapDirty(true)
  }, [])

  const moveMajorStep = useCallback((idx, dir) => {
    setEditableMajorSteps((prev) => {
      const j = idx + dir
      if (j < 0 || j >= prev.length) return prev
      const next = [...prev]
      const t = next[idx]
      next[idx] = next[j]
      next[j] = t
      return reindexMajorSteps(next)
    })
    setRoadmapDirty(true)
  }, [])

  const removeMajorStep = useCallback((idx) => {
    setEditableMajorSteps((prev) => {
      if (prev.length <= 2) return prev
      return reindexMajorSteps(prev.filter((_, i) => i !== idx))
    })
    setRoadmapDirty(true)
  }, [])

  const addMajorStep = useCallback(() => {
    setEditableMajorSteps((prev) => {
      if (prev.length >= PATH_STEPS_HARD_MAX) return prev
      const phase = ROADMAP_PHASES[Math.min(prev.length, ROADMAP_PHASES.length - 1)]
      return reindexMajorSteps([
        ...prev,
        {
          index: prev.length,
          phase,
          learning_goal: '',
          consolidates: [],
          rationale: '',
        },
      ])
    })
    setRoadmapDirty(true)
  }, [])

  const moveStep = useCallback((idx, dir) => {
    setPathSteps((prev) => {
      const j = idx + dir
      if (j < 0 || j >= prev.length) return prev
      const next = [...prev]
      const t = next[idx]
      next[idx] = next[j]
      next[j] = t
      return next
    })
  }, [])

  const applyOffTopicFlags = (rows, qa) => {
    const off = Array.isArray(qa?.off_topic_steps) ? qa.off_topic_steps : []
    const indices = new Set(off.map((o) => Number(o.step_index)).filter(Number.isFinite))
    return rows.map((row, idx) => ({ ...row, isOffTopic: indices.has(idx) }))
  }

  const trimPathToMaxSteps = useCallback((rows, limit) => {
    let next = [...rows]
    while (next.length > limit) {
      const offIdx = next.findIndex((s) => s.isOffTopic)
      if (offIdx >= 0) {
        next.splice(offIdx, 1)
        continue
      }
      next.pop()
    }
    return next.map((r) => ({ ...r, isOffTopic: false }))
  }, [])

  const insertExerciseFromOffer = useCallback(
    (created, offer) => {
      const row = mapCreatedExerciseToRow(created, offer)
      setPathSteps((prev) => {
        let next = [...prev]
        const afterIdx = Number(offer?.insert_after_index)
        const replaceIdx =
          offer?.replace_step_index != null ? Number(offer.replace_step_index) : null

        if (Number.isFinite(replaceIdx) && replaceIdx >= 0 && replaceIdx < next.length) {
          next.splice(replaceIdx, 1, row)
        } else if (Number.isFinite(afterIdx) && afterIdx >= 0 && afterIdx < next.length) {
          next.splice(afterIdx + 1, 0, row)
        } else {
          next.push(row)
        }
        return trimPathToMaxSteps(next, maxSteps)
      })
      setGapFillOffers((prev) => prev.filter((o) => o.offer_id !== offer?.offer_id))
    },
    [maxSteps, trimPathToMaxSteps],
  )

  const closeQuickCreate = () => {
    if (quickSaving) return
    setQuickCreateOpen(false)
    setActiveOffer(null)
    setQuickCreateDraft(null)
    setQuickAiError('')
  }

  const handleGapFillClick = async (offer) => {
    if (!confirmPathExpansionIfNeeded(offer, pathSteps.length, maxSteps, setMaxSteps)) {
      return
    }
    await runGapFillAiSuggest(offer)
  }

  const gapContextFallbackParams = {
    goalQuery,
    semanticBrief,
    graphId,
    pathSteps,
    editableMajorSteps,
    progressionRoadmap,
    startSituation,
    targetState,
    roadmapNotes,
  }

  const runGapFillAiSuggest = async (offer) => {
    const title = (offer?.title_hint || '').trim()
    if (title.length < 3) {
      alert('Titel-Hinweis fehlt — bitte Pfad erneut vorschlagen.')
      return
    }
    const goalText = (offer?.goal_for_ai || offer?.sketch || '').trim()
    const focusId = resolveDefaultFocusAreaId(targetSummary, focusAreas)
    if (!focusId) {
      alert('Kein Fokusbereich verfügbar — bitte Kataloge laden oder manuell wählen.')
      setQuickTitle(title)
      setQuickSketch(goalText)
      setQuickFocusAreaId('')
      setActiveOffer(offer)
      setQuickCreateOpen(true)
      return
    }
    const focusRow = (focusAreas || []).find((x) => Number(x.id) === focusId)
    const focusHint = (focusRow?.name || offer?.primary_topic || '').trim()

    setActiveOffer(offer)
    setQuickTitle(title)
    setQuickSketch(goalText)
    setQuickFocusAreaId(String(focusId))
    setQuickAiError('')
    setQuickCreateDraft(null)
    setQuickSaving(true)
    setGeneratingOfferId(offer?.offer_id || null)
    const contextLines = gapOfferContextDisplayLines(offer, gapContextFallbackParams)
    setActivePlanningContextLines(contextLines)
    const planningContext = buildPathGapPlanningContextForAi({
      offer,
      ...gapContextFallbackParams,
    })
    try {
      const aiRes = await api.suggestExerciseAi({
        title,
        goal: goalText || undefined,
        execution: '',
        preparation: '',
        trainer_notes: '',
        focus_area_hint: focusHint || undefined,
        focus_areas_context: [{ focus_area_id: focusId, is_primary: true }],
        planning_context: planningContext || undefined,
        include_summary: true,
        include_skills: true,
        include_instructions: true,
      })
      const preview = buildQuickCreateAiPreview(aiRes, { sketchPlain: goalText })
      if (!preview.hasSummaryProposal && !preview.hasInstructionChoices && !preview.hasSkillChoices) {
        throw new Error('Die KI lieferte keinen verwertbaren Vorschlag.')
      }
      setQuickCreateDraft(
        aiPreviewToQuickCreateDraft(preview, {
          title,
          focusAreaId: focusId,
          sketchPlain: goalText,
        }),
      )
      setQuickCreateOpen(false)
    } catch (e) {
      console.error(e)
      const msg = e?.message || String(e)
      setQuickAiError(msg)
      setQuickCreateOpen(true)
    } finally {
      setQuickSaving(false)
      setGeneratingOfferId(null)
    }
  }

  const runQuickCreateAiSuggest = async () => {
    const title = (quickTitle || '').trim()
    if (title.length < 3) {
      alert('Titel: mindestens 3 Zeichen.')
      return
    }
    const sketch = (quickSketch || '').trim()
    const focusId = parseInt(String(quickFocusAreaId).trim(), 10)
    if (!Number.isFinite(focusId) || focusId < 1) {
      alert('Bitte einen Fokusbereich wählen.')
      return
    }
    const focusRow = (focusAreas || []).find((x) => Number(x.id) === focusId)
    const focusHint = (focusRow?.name || '').trim()

    setQuickAiError('')
    setQuickCreateDraft(null)
    setQuickSaving(true)
    try {
      const aiRes = await api.suggestExerciseAi({
        title,
        goal: sketch || undefined,
        execution: '',
        preparation: '',
        trainer_notes: '',
        focus_area_hint: focusHint || undefined,
        focus_areas_context: [{ focus_area_id: focusId, is_primary: true }],
        include_summary: true,
        include_skills: true,
        include_instructions: true,
      })
      const preview = buildQuickCreateAiPreview(aiRes, { sketchPlain: sketch })
      if (!preview.hasSummaryProposal && !preview.hasInstructionChoices && !preview.hasSkillChoices) {
        throw new Error('Die KI lieferte keinen verwertbaren Vorschlag.')
      }
      setQuickCreateDraft(
        aiPreviewToQuickCreateDraft(preview, { title, focusAreaId: focusId, sketchPlain: sketch }),
      )
      setQuickCreateOpen(false)
    } catch (e) {
      console.error(e)
      const msg = e?.message || String(e)
      setQuickAiError(msg)
      alert(msg || 'KI-Vorschlag fehlgeschlagen')
    } finally {
      setQuickSaving(false)
    }
  }

  const applyQuickCreateDraft = async () => {
    if (!quickCreateDraft || !activeOffer) return
    setQuickSaving(true)
    setQuickAiError('')
    try {
      const payload = buildQuickCreateExercisePayloadFromDraft(quickCreateDraft)
      const created = await api.createExercise(payload)
      if (!created?.id) throw new Error('Anlegen fehlgeschlagen')
      insertExerciseFromOffer(created, activeOffer)
      setQuickCreateDraft(null)
      setActiveOffer(null)
    } catch (e) {
      console.error(e)
      const msg = e?.message || String(e)
      setQuickAiError(msg)
      alert(msg || 'Übung konnte nicht angelegt werden')
    } finally {
      setQuickSaving(false)
    }
  }

  const applyPathMatchResponse = (res, q) => {
    const qa = res?.path_qa || null
    const rawRows = (Array.isArray(res?.steps) ? res.steps : []).map(mapApiStepToRow)
    const rows =
      Array.isArray(qa?.stripped_off_topic_steps) && qa.stripped_off_topic_steps.length > 0
        ? rawRows
        : applyOffTopicFlags(rawRows, qa)
    if (rows.length < 2) {
      throw new Error('Zu wenig Schritte im Vorschlag.')
    }
    setPathSteps(rows)
    setTargetSummary(res?.target_profile_summary || null)
    setSemanticBrief(res?.semantic_brief_summary || null)
    setPathQa(qa)
    setGapFillOffers(
      Array.isArray(res?.gap_fill_offers)
        ? res.gap_fill_offers
        : Array.isArray(qa?.gap_fill_offers)
          ? qa.gap_fill_offers
          : [],
    )
    setProgressionRoadmap(res?.progression_roadmap || null)
    setRoadmapDirty(false)
    if (!segmentNotes.trim() && q) setSegmentNotes(q.slice(0, 400))
  }

  const applyStartTargetResponse = (res) => {
    const roadmap = res?.progression_roadmap || null
    setProgressionRoadmap((prev) => ({
      ...(prev || {}),
      ...roadmap,
      roadmap: prev?.roadmap || roadmap?.roadmap || null,
      stage_specs: prev?.stage_specs || roadmap?.stage_specs || [],
    }))
    applyResolvedStructuredFromRoadmap(roadmap, {
      setStartSituation,
      setTargetState,
      setRoadmapNotes,
    })
    setSemanticBrief(res?.semantic_brief_summary || null)
    setStartTargetAnalyzed(true)
  }

  const analyzeStartTarget = async () => {
    const q = (goalQuery || '').trim()
    if (q.length < 3) {
      alert('Ziel-Anfrage: mindestens 3 Zeichen.')
      return
    }
    if (!graphId) {
      alert('Zuerst einen Graphen wählen.')
      return
    }
    setLoadingStartTarget(true)
    setError('')
    try {
      const res = await api.suggestProgressionPath({
        query: q,
        max_steps: Number(maxSteps),
        include_llm_intent: false,
        include_path_qa: false,
        include_llm_path_qa: false,
        include_path_reorder: false,
        include_ai_gap_fill: false,
        include_roadmap_preview: false,
        include_llm_roadmap: false,
        include_llm_start_target: true,
        start_target_only: true,
        progression_graph_id: Number(graphId),
        ...roadmapStructuredPayload(startSituation, targetState, roadmapNotes),
      })
      applyStartTargetResponse(res)
    } catch (e) {
      console.error(e)
      setError(e.message || 'Start/Ziel-Analyse fehlgeschlagen')
    } finally {
      setLoadingStartTarget(false)
    }
  }

  const suggestRoadmap = async () => {
    const q = (goalQuery || '').trim()
    if (q.length < 3) {
      alert('Ziel-Anfrage: mindestens 3 Zeichen.')
      return
    }
    if (!graphId) {
      alert('Zuerst einen Graphen wählen.')
      return
    }
    const fieldsEmpty = !startSituation.trim() && !targetState.trim()
    setLoadingRoadmap(true)
    setError('')
    try {
      const res = await api.suggestProgressionPath({
        query: q,
        max_steps: Number(maxSteps),
        include_llm_intent: false,
        include_path_qa: false,
        include_llm_path_qa: false,
        include_path_reorder: false,
        include_ai_gap_fill: false,
        include_roadmap_preview: true,
        include_llm_roadmap: true,
        include_llm_start_target: fieldsEmpty,
        roadmap_only: true,
        progression_graph_id: Number(graphId),
        ...roadmapStructuredPayload(startSituation, targetState, roadmapNotes),
      })
      const majors = mapMajorStepsFromApi(res?.progression_roadmap)
      if (majors.length < 2) {
        throw new Error('Roadmap hat zu wenig Major Steps.')
      }
      setEditableMajorSteps(majors)
      setMaxSteps(majors.length)
      const roadmap = res?.progression_roadmap || null
      setProgressionRoadmap(roadmap)
      if (fieldsEmpty) {
        applyResolvedStructuredFromRoadmap(roadmap, {
          setStartSituation,
          setTargetState,
          setRoadmapNotes,
        })
        setStartTargetAnalyzed(true)
      }
      setSemanticBrief(res?.semantic_brief_summary || null)
      setPathSteps([])
      setTargetSummary(null)
      setPathQa(null)
      setGapFillOffers([])
      setRoadmapDirty(false)
    } catch (e) {
      console.error(e)
      setError(e.message || 'Roadmap-Vorschlag fehlgeschlagen')
      setEditableMajorSteps([])
      setProgressionRoadmap(null)
    } finally {
      setLoadingRoadmap(false)
    }
  }

  const matchExercisesFromRoadmap = async () => {
    const q = (goalQuery || '').trim()
    if (q.length < 3) {
      alert('Ziel-Anfrage: mindestens 3 Zeichen.')
      return
    }
    if (!graphId) {
      alert('Zuerst einen Graphen wählen.')
      return
    }
    const validSteps = editableMajorSteps.filter((s) => (s.learning_goal || '').trim().length >= 3)
    if (validSteps.length < 2) {
      alert('Mindestens zwei Major Steps mit Lernziel (je 3+ Zeichen) nötig.')
      return
    }
    setLoadingMatch(true)
    setError('')
    try {
      const override = majorStepsToOverridePayload(validSteps)
      const res = await api.suggestProgressionPath({
        query: q,
        max_steps: validSteps.length,
        include_llm_intent: true,
        include_path_qa: true,
        include_llm_path_qa: true,
        include_path_reorder: true,
        include_ai_gap_fill: true,
        include_roadmap_preview: true,
        include_llm_roadmap: false,
        roadmap_first: true,
        roadmap_override: override,
        progression_graph_id: Number(graphId),
        ...roadmapStructuredPayload(startSituation, targetState, roadmapNotes),
      })
      applyPathMatchResponse(res, q)
      setMaxSteps(validSteps.length)
    } catch (e) {
      console.error(e)
      setError(e.message || 'Übungs-Match fehlgeschlagen')
    } finally {
      setLoadingMatch(false)
    }
  }

  const savePathToGraph = async () => {
    if (!graphId) {
      alert('Zuerst einen Graphen wählen.')
      return
    }
    const steps = pathSteps.filter((s) => s.exerciseId != null)
    const skippedAi = pathSteps.filter((s) => s.isAiProposal).length
    if (steps.length < 2) {
      alert(
        skippedAi > 0
          ? 'Mindestens zwei gespeicherte Übungen nötig. KI-Vorschläge zuerst als Übung anlegen.'
          : 'Mindestens zwei Schritte mit Übung nötig.',
      )
      return
    }
    const n = steps.length - 1
    const noteRaw = segmentNotes.trim()
    const segment_notes = Array.from({ length: n }, (_, i) => {
      const reasons = (steps[i + 1]?.reasons || []).slice(0, 2).join(' · ')
      if (reasons) return reasons
      return noteRaw || null
    })

    setSaving(true)
    setError('')
    try {
      await api.createExerciseProgressionSequence(Number(graphId), {
        steps: steps.map((s) => ({
          exercise_id: s.exerciseId,
          variant_id: s.variantId || null,
        })),
        segment_notes,
      })
      setPathSteps([])
      setTargetSummary(null)
      setSemanticBrief(null)
      setPathQa(null)
      setGapFillOffers([])
      setProgressionRoadmap(null)
      setEditableMajorSteps([])
      setRoadmapDirty(false)
      if (typeof onSaved === 'function') await onSaved()
      const msg =
        skippedAi > 0
          ? `${n} Kante(n) gespeichert. ${skippedAi} KI-Vorschlag/Vorschläge nicht im Graph (noch nicht angelegt).`
          : `${n} Nachfolger-Kante(n) aus KI-Pfad gespeichert.`
      alert(msg)
    } catch (e) {
      console.error(e)
      setError(e.message || 'Speichern fehlgeschlagen')
    } finally {
      setSaving(false)
    }
  }

  return (
    <div
      className="card"
      style={{
        marginBottom: '12px',
        borderColor: 'color-mix(in srgb, var(--accent) 35%, var(--border))',
      }}
    >
      <h3 style={{ marginTop: 0, fontSize: '1rem' }}>KI: Pfad zum Ziel</h3>
      <p style={{ fontSize: '12px', color: 'var(--text3)', marginTop: 0, lineHeight: 1.45 }}>
        Zuerst didaktische Roadmap vorschlagen und anpassen, dann Übungen je Major Step aus der Bibliothek matchen.
        Lücken können mit KI als Übung angelegt werden.
      </p>
      <div style={{ display: 'flex', flexWrap: 'wrap', gap: '10px', alignItems: 'flex-end' }}>
        <div className="form-row" style={{ flex: '2 1 240px', marginBottom: 0 }}>
          <label className="form-label">Ziel / Entwicklungsrichtung</label>
          <input
            className="form-input"
            value={goalQuery}
            onChange={(e) => setGoalQuery(e.target.value)}
            placeholder="z. B. Von Erlernen bis zur Perfektion des Fußtritts Mae Geri …"
            disabled={disabled || loading || saving}
          />
        </div>
        <div className="form-row" style={{ flex: '0 1 120px', marginBottom: 0 }}>
          <label className="form-label">Schritte</label>
          <input
            type="number"
            min={2}
            max={10}
            className="form-input"
            value={maxSteps}
            onChange={(e) => setMaxSteps(Math.max(2, Math.min(10, Number(e.target.value) || 5)))}
            disabled={disabled || loading || saving}
          />
        </div>
      </div>
      <div
        style={{
          display: 'grid',
          gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))',
          gap: '10px',
          marginTop: '10px',
        }}
      >
        <div className="form-row" style={{ marginBottom: 0 }}>
          <label className="form-label">Startpunkt / Ausgangslage</label>
          <textarea
            className="form-input"
            rows={2}
            value={startSituation}
            onChange={(e) => setStartSituation(e.target.value)}
            placeholder="z. B. gleichartige Steppbewegung, vorhersehbar"
            disabled={disabled || loading || saving}
          />
        </div>
        <div className="form-row" style={{ marginBottom: 0 }}>
          <label className="form-label">Zielzustand</label>
          <textarea
            className="form-input"
            rows={2}
            value={targetState}
            onChange={(e) => setTargetState(e.target.value)}
            placeholder="z. B. dynamische, unvorhersehbare Bewegung mit explosivem Angriff und Ausweichen"
            disabled={disabled || loading || saving}
          />
        </div>
        <div className="form-row" style={{ marginBottom: 0 }}>
          <label className="form-label">Ergänzungen (Fokus, Gruppe, Besonderheiten)</label>
          <textarea
            className="form-input"
            rows={2}
            value={roadmapNotes}
            onChange={(e) => setRoadmapNotes(e.target.value)}
            placeholder="optional: Altersgruppe, Kumite-Kontext, Trainingsfokus …"
            disabled={disabled || loading || saving}
          />
        </div>
      </div>
      <p style={{ fontSize: '11px', color: 'var(--text3)', margin: '6px 0 0', lineHeight: 1.4 }}>
        Optional zuerst „Start/Ziel analysieren“, anpassen, dann Roadmap-Stufen. Sind Start und Ziel leer,
        geschieht die Analyse beim Roadmap-Vorschlag automatisch mit. Manuelle Eingaben haben immer Vorrang.
      </p>
      <div style={{ display: 'flex', flexWrap: 'wrap', gap: '10px', alignItems: 'flex-end', marginTop: '10px' }}>
        <button
          type="button"
          className="btn btn-secondary"
          disabled={disabled || loading || saving || !graphId}
          onClick={analyzeStartTarget}
          title="Nur Ausgangslage, Zielzustand und Ergänzungen per KI — ohne Roadmap-Stufen"
        >
          {loadingStartTarget ? 'Analyse …' : 'Start/Ziel analysieren'}
        </button>
        <button
          type="button"
          className="btn btn-primary"
          disabled={disabled || loading || saving || !graphId}
          onClick={suggestRoadmap}
          title={
            startSituation.trim() && targetState.trim()
              ? 'Roadmap-Stufen aus den gesetzten Start/Ziel-Feldern'
              : 'Start/Ziel-Analyse und Roadmap-Stufen in einem Schritt'
          }
        >
          {loadingRoadmap ? 'Roadmap …' : 'Roadmap vorschlagen'}
        </button>
        {startTargetAnalyzed && !editableMajorSteps.length ? (
          <span className="exercise-tag" style={{ borderColor: 'var(--accent)' }}>
            Start/Ziel bereit — Roadmap als Nächstes
          </span>
        ) : null}
        <button
          type="button"
          className="btn btn-secondary"
          disabled={
            disabled ||
            loading ||
            saving ||
            !graphId ||
            editableMajorSteps.length < 2
          }
          onClick={matchExercisesFromRoadmap}
          title={
            editableMajorSteps.length < 2
              ? 'Zuerst Roadmap vorschlagen'
              : roadmapDirty
                ? 'Roadmap wurde bearbeitet — erneut matchen'
                : 'Bibliothek je Major Step durchsuchen'
          }
        >
          {loadingMatch ? 'Match …' : roadmapDirty ? 'Übungen neu matchen' : 'Übungen matchen'}
        </button>
      </div>

      {error ? (
        <p className="form-error" style={{ marginTop: '10px' }}>
          {error}
        </p>
      ) : null}

      {(progressionRoadmap?.goal_analysis ||
        progressionRoadmap?.pipeline_phase === 'start_target_only') ? (
        <div
          style={{
            marginTop: '12px',
            padding: '12px',
            borderRadius: '8px',
            border: '1px solid var(--border)',
            background: 'var(--surface2)',
          }}
        >
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px', alignItems: 'center', marginBottom: '8px' }}>
            <strong style={{ fontSize: '13px' }}>Zielanalyse</strong>
            {progressionRoadmap.llm_start_target_applied ? (
              <span className="exercise-tag" style={{ borderColor: 'var(--accent)' }}>
                KI Start/Ziel
              </span>
            ) : null}
            {progressionRoadmap.llm_goal_analysis_applied ? (
              <span className="exercise-tag" style={{ borderColor: 'var(--accent)' }}>
                KI-Zielanalyse
              </span>
            ) : (
              <span className="exercise-tag">heuristisch</span>
            )}
            {progressionRoadmap.start_target_sources ? (
              <span className="exercise-tag" style={{ fontSize: '11px' }}>
                Start: {sourceLabel(progressionRoadmap.start_target_sources.start)} · Ziel:{' '}
                {sourceLabel(progressionRoadmap.start_target_sources.target)}
              </span>
            ) : null}
            {progressionRoadmap.goal_analysis.primary_topic ? (
              <span className="exercise-tag">Thema: {progressionRoadmap.goal_analysis.primary_topic}</span>
            ) : null}
          </div>
          <div style={{ fontSize: '12px', color: 'var(--text2)', lineHeight: 1.5 }}>
            <div>
              <span style={{ color: 'var(--text3)' }}>Ausgang: </span>
              {progressionRoadmap.goal_analysis.start_assumption}
            </div>
            <div style={{ marginTop: '6px' }}>
              <span style={{ color: 'var(--text3)' }}>Ziel: </span>
              {progressionRoadmap.goal_analysis.target_state}
            </div>
            {Array.isArray(progressionRoadmap.goal_analysis.success_criteria) &&
            progressionRoadmap.goal_analysis.success_criteria.length > 0 ? (
              <ul style={{ margin: '8px 0 0', paddingLeft: '18px' }}>
                {progressionRoadmap.goal_analysis.success_criteria.slice(0, 4).map((c) => (
                  <li key={c}>{c}</li>
                ))}
              </ul>
            ) : null}
            {progressionRoadmap.start_target_extract?.extraction_notes ? (
              <p style={{ margin: '8px 0 0', fontSize: '11px', color: 'var(--text3)' }}>
                {progressionRoadmap.start_target_extract.extraction_notes}
              </p>
            ) : null}
          </div>
        </div>
      ) : null}

      {(semanticBrief || targetSummary) && pathSteps.length > 0 ? (
        <div style={{ marginTop: '10px', display: 'flex', flexWrap: 'wrap', gap: '6px' }}>
          {semanticBrief?.primary_topic ? (
            <span className="exercise-tag" style={{ borderColor: 'var(--accent)' }}>
              Thema: {semanticBrief.primary_topic}
            </span>
          ) : null}
          {Array.isArray(semanticBrief?.development_arc) &&
            semanticBrief.development_arc.slice(0, 3).map((phase) => (
              <span key={phase} className="exercise-tag">
                {phase}
              </span>
            ))}
          {Array.isArray(targetSummary?.focus_areas) &&
            targetSummary.focus_areas.slice(0, 1).map((fa) => (
              <span key={fa} className="exercise-tag">
                Fokus: {fa}
              </span>
            ))}
        </div>
      ) : null}

      {editableMajorSteps.length > 0 ? (
        <div
          style={{
            marginTop: '12px',
            padding: '12px',
            borderRadius: '8px',
            border: '1px solid color-mix(in srgb, var(--accent) 45%, var(--border))',
            background: 'color-mix(in srgb, var(--accent) 6%, var(--surface))',
          }}
        >
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px', alignItems: 'center', marginBottom: '8px' }}>
            <strong style={{ fontSize: '13px' }}>Didaktische Roadmap — bearbeiten</strong>
            {roadmapDirty ? (
              <span className="exercise-tag" style={{ borderColor: 'var(--danger)' }}>
                Geändert — bitte erneut matchen
              </span>
            ) : pathSteps.length > 0 ? (
              <span className="exercise-tag" style={{ borderColor: 'var(--accent)' }}>
                Gematcht
              </span>
            ) : null}
          </div>
          <p style={{ fontSize: '12px', color: 'var(--text3)', margin: '0 0 10px', lineHeight: 1.45 }}>
            {progressionRoadmap?.micro_objective_count != null
              ? `${progressionRoadmap.micro_objective_count} Zwischenziele → `
              : ''}
            {editableMajorSteps.length} Major Steps
            {progressionRoadmap?.llm_roadmap_applied
              ? ' (KI-Roadmap)'
              : progressionRoadmap
                ? ' (heuristisch/KI)'
                : ''}
            . Phasen und Lernziele anpassen, dann „Übungen matchen“.
          </p>
          <div style={{ display: 'flex', flexDirection: 'column', gap: '10px' }}>
            {editableMajorSteps.map((step, idx) => (
              <div
                key={`major-${idx}-${step.index}`}
                style={{
                  padding: '10px 12px',
                  borderRadius: '8px',
                  background: 'var(--surface2)',
                  border: '1px solid var(--border)',
                  display: 'grid',
                  gridTemplateColumns: 'repeat(auto-fit, minmax(160px, 1fr))',
                  gap: '10px',
                  alignItems: 'end',
                }}
              >
                <div className="form-row" style={{ marginBottom: 0, flex: '0 0 120px' }}>
                  <label className="form-label">Stufe {idx + 1} · Phase</label>
                  <select
                    className="form-input"
                    value={step.phase}
                    onChange={(e) => patchMajorStep(idx, { phase: e.target.value })}
                    disabled={disabled || loading || saving}
                  >
                    {ROADMAP_PHASES.map((p) => (
                      <option key={p} value={p}>
                        {p}
                      </option>
                    ))}
                  </select>
                </div>
                <div className="form-row" style={{ marginBottom: 0, flex: '2 1 240px' }}>
                  <label className="form-label">Lernziel</label>
                  <input
                    className="form-input"
                    value={step.learning_goal}
                    onChange={(e) => patchMajorStep(idx, { learning_goal: e.target.value })}
                    placeholder="z. B. Grundstellung und Hüftmobilität für Mae Geri"
                    disabled={disabled || loading || saving}
                  />
                </div>
                <div style={{ display: 'flex', gap: '6px', flexWrap: 'wrap' }}>
                  <button
                    type="button"
                    className="btn"
                    style={{ fontSize: '12px', padding: '4px 8px' }}
                    onClick={() => moveMajorStep(idx, -1)}
                    disabled={disabled || loading || saving || idx === 0}
                  >
                    ↑
                  </button>
                  <button
                    type="button"
                    className="btn"
                    style={{ fontSize: '12px', padding: '4px 8px' }}
                    onClick={() => moveMajorStep(idx, 1)}
                    disabled={disabled || loading || saving || idx >= editableMajorSteps.length - 1}
                  >
                    ↓
                  </button>
                  <button
                    type="button"
                    className="btn"
                    style={{ fontSize: '12px', padding: '4px 8px' }}
                    onClick={() => removeMajorStep(idx)}
                    disabled={disabled || loading || saving || editableMajorSteps.length <= 2}
                  >
                    Entfernen
                  </button>
                </div>
              </div>
            ))}
          </div>
          {editableMajorSteps.length < PATH_STEPS_HARD_MAX ? (
            <button
              type="button"
              className="btn btn-secondary"
              style={{ marginTop: '10px', fontSize: '12px' }}
              onClick={addMajorStep}
              disabled={disabled || loading || saving}
            >
              Major Step hinzufügen
            </button>
          ) : null}
        </div>
      ) : null}

      {pathQa && pathSteps.length > 0 ? (
        <div
          style={{
            marginTop: '10px',
            padding: '10px 12px',
            borderRadius: '8px',
            background: pathQa.overall_ok ? 'color-mix(in srgb, var(--accent) 8%, var(--surface2))' : 'color-mix(in srgb, var(--danger) 8%, var(--surface2))',
            fontSize: '12px',
            lineHeight: 1.45,
          }}
        >
          <strong>
            Pfad-QS: {pathQa.overall_ok ? 'OK' : 'Hinweise'}
            {pathQa.quality_score != null ? ` (${Math.round(Number(pathQa.quality_score) * 100)} %)` : ''}
          </strong>
          {pathQa.topic_coverage ? (
            <p style={{ margin: '6px 0 0', color: 'var(--text2)' }}>{pathQa.topic_coverage}</p>
          ) : null}
          {Array.isArray(pathQa.issues) && pathQa.issues.length > 0 ? (
            <ul style={{ margin: '6px 0 0', paddingLeft: '16px', color: 'var(--text2)' }}>
              {pathQa.issues.slice(0, 4).map((issue) => (
                <li key={issue}>{issue}</li>
              ))}
            </ul>
          ) : null}
          {Number(pathQa.bridge_insert_count) > 0 ? (
            <p style={{ margin: '6px 0 0', color: 'var(--accent-dark)' }}>
              {pathQa.bridge_insert_count} Brücken-Übung(en) aus der Bibliothek eingefügt.
            </p>
          ) : null}
          {Array.isArray(pathQa.stripped_off_topic_steps) && pathQa.stripped_off_topic_steps.length > 0 ? (
            <p style={{ margin: '6px 0 0', color: 'var(--accent-dark)' }}>
              {pathQa.stripped_off_topic_steps.length} themenfremde(r) Schritt(e) aus dem Pfad entfernt:{' '}
              {pathQa.stripped_off_topic_steps.map((s) => s.removed_title || s.title).join(', ')}.
            </p>
          ) : Number(pathQa.off_topic_count) > 0 ? (
            <p style={{ margin: '6px 0 0', color: 'var(--danger)' }}>
              {pathQa.off_topic_count} Schritt(e) ohne Bezug zum Pfad-Thema — siehe Lücken-Angebote unten.
            </p>
          ) : null}
          {pathQa.reorder_applied ? (
            <p style={{ margin: '6px 0 0', color: 'var(--text2)' }}>
              Reihenfolge nach QS angepasst.
              {Array.isArray(pathQa.reorder_notes) && pathQa.reorder_notes[0]
                ? ` ${pathQa.reorder_notes[0]}`
                : ''}
            </p>
          ) : null}
          {pathQa.roadmap_qa_mode === 'roadmap_first_lite' ? (
            <p style={{ margin: '6px 0 0', color: 'var(--text2)' }}>
              QS an Roadmap gekoppelt: keine Brücken/Reihenfolge zwischen Major Steps (didaktisch bereits geplant).
            </p>
          ) : null}
        </div>
      ) : null}

      {gapFillOffers.length > 0 ? (
        <div
          style={{
            marginTop: '12px',
            padding: '12px',
            borderRadius: '8px',
            border: '1px solid color-mix(in srgb, var(--accent) 40%, var(--border))',
            background: 'color-mix(in srgb, var(--accent) 5%, var(--surface))',
          }}
        >
          <strong style={{ fontSize: '13px' }}>Fehlende Schritte — mit KI anlegen</strong>
          <p style={{ fontSize: '12px', color: 'var(--text3)', margin: '6px 0 10px', lineHeight: 1.45 }}>
            Fehlende oder zu ersetzende Schritte ({pathSteps.length}/{maxSteps} im Pfad).
            {pathSteps.length >= maxSteps
              ? ' Der Pfad ist voll — beim Einfügen können Sie die Pfadlänge dynamisch vergrößern (ohne neuen Vorschlag); Ersatz-Angebote ersetzen einen Schritt.'
              : ' „Mit KI anlegen“ erzeugt einen vollständigen Entwurf und fügt die Übung ein.'}
          </p>
          <div style={{ display: 'flex', flexDirection: 'column', gap: '10px' }}>
            {gapFillOffers.map((offer) => (
              <div
                key={offer.offer_id}
                style={{
                  padding: '10px 12px',
                  borderRadius: '8px',
                  background: 'var(--surface2)',
                  border: '1px solid var(--border)',
                }}
              >
                <div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px', alignItems: 'flex-start' }}>
                  <div style={{ flex: '1 1 200px' }}>
                    <span className="exercise-tag" style={{ marginBottom: '6px', display: 'inline-block' }}>
                      {OFFER_SOURCE_LABELS[offer.source] || offer.source || 'Lücke'}
                      {offer.phase ? ` · ${offer.phase}` : ''}
                    </span>
                    <div style={{ fontSize: '13px', fontWeight: 600 }}>{offer.title_hint}</div>
                    {offer.rationale ? (
                      <p style={{ fontSize: '12px', color: 'var(--text2)', margin: '4px 0 0' }}>{offer.rationale}</p>
                    ) : null}
                    {offer.from_title && offer.to_title ? (
                      <p style={{ fontSize: '11px', color: 'var(--text3)', margin: '4px 0 0' }}>
                        Zwischen „{offer.from_title}“ und „{offer.to_title}“
                        {offer.replace_step_index != null ? ' (ersetzt themenfremden Schritt)' : ''}
                      </p>
                    ) : null}
                    <GapOfferContextPreview
                      lines={gapOfferContextDisplayLines(offer, gapContextFallbackParams)}
                    />
                  </div>
                  <button
                    type="button"
                    className="btn btn-primary"
                    style={{ fontSize: '12px', flexShrink: 0 }}
                    disabled={
                      quickSaving ||
                      (isGapOfferBlockedByPathCapacity(offer, pathSteps.length, maxSteps) &&
                        maxSteps >= PATH_STEPS_HARD_MAX)
                    }
                    onClick={() => handleGapFillClick(offer)}
                    title={
                      isGapOfferBlockedByPathCapacity(offer, pathSteps.length, maxSteps)
                        ? maxSteps >= PATH_STEPS_HARD_MAX
                          ? `Maximal ${PATH_STEPS_HARD_MAX} Schritte — zuerst einen Schritt entfernen.`
                          : 'Pfad voll — Klick fragt, ob die Pfadlänge vergrößert werden soll'
                        : offer.replace_step_index != null
                          ? 'Ersetzt den themenfremden Schritt im Pfad'
                          : 'KI-Entwurf mit Pfad-Kontext generieren'
                    }
                  >
                    {generatingOfferId === offer.offer_id
                      ? 'KI erstellt Entwurf …'
                      : 'Mit KI anlegen'}
                  </button>
                </div>
              </div>
            ))}
          </div>
        </div>
      ) : null}

      {pathSteps.length > 0 ? (
        <>
          <div style={{ marginTop: '14px' }}>
            {pathSteps.map((step, idx) => (
              <div
                key={`${step.exerciseId}-${step.proposalKey || ''}-${idx}`}
                style={{
                  display: 'grid',
                  gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))',
                  gap: '10px',
                  alignItems: 'end',
                  marginBottom: '12px',
                  paddingBottom: '12px',
                  borderBottom: idx < pathSteps.length - 1 ? '1px dashed var(--border)' : 'none',
                  background: step.isOffTopic
                    ? 'color-mix(in srgb, var(--danger) 6%, transparent)'
                    : undefined,
                  borderRadius: step.isOffTopic ? '8px' : undefined,
                  padding: step.isOffTopic ? '8px' : undefined,
                }}
              >
                <div className="form-row" style={{ marginBottom: 0 }}>
                  <label className="form-label">
                    Schritt {idx + 1}
                    {step.roadmapMajorStepIndex != null
                      ? ` · Roadmap ${step.roadmapMajorStepIndex + 1}`
                      : ''}
                    {step.roadmapPhase ? ` (${step.roadmapPhase})` : ''}
                    {step.isOffTopic ? ' (themenfremd)' : ''}
                    {step.isAiProposal ? ' (KI-Neu)' : step.isBridge ? ' (Brücke)' : ''}
                  </label>
                  {step.roadmapLearningGoal ? (
                    <p style={{ fontSize: '11px', color: 'var(--text3)', margin: '4px 0 0' }}>
                      Ziel: {step.roadmapLearningGoal}
                    </p>
                  ) : null}
                  <div style={{ fontSize: '13px' }}>
                    <strong>{step.exerciseTitle}</strong>
                    {step.exerciseId ? (
                      <span style={{ color: 'var(--text3)' }}> (#{step.exerciseId})</span>
                    ) : (
                      <span style={{ color: 'var(--text3)' }}> — noch nicht in Bibliothek</span>
                    )}
                  </div>
                  {step.reasons?.length ? (
                    <ul
                      style={{
                        margin: '6px 0 0',
                        paddingLeft: '16px',
                        fontSize: '11px',
                        color: 'var(--accent-dark)',
                      }}
                    >
                      {step.reasons.slice(0, 2).map((r) => (
                        <li key={r}>{r}</li>
                      ))}
                    </ul>
                  ) : null}
                </div>
                <div className="form-row" style={{ marginBottom: 0 }}>
                  <label className="form-label">Variante</label>
                  {step.isAiProposal ? (
                    <p style={{ fontSize: '12px', color: 'var(--text3)', margin: 0 }}>
                      Nach Anlage der Übung im Graph wählbar.
                    </p>
                  ) : (
                    <select
                      className="form-input"
                      value={step.variantId ?? ''}
                      onChange={(e) =>
                        patchStep(idx, {
                          variantId: e.target.value === '' ? null : parseInt(e.target.value, 10),
                        })
                      }
                      disabled={!step.exerciseId}
                    >
                      <option value="">Gesamte Übung</option>
                      {(step.variants || []).map((v) => (
                        <option key={v.id} value={v.id}>
                          {v.variant_name || `Variante #${v.id}`}
                        </option>
                      ))}
                    </select>
                  )}
                </div>
                <div style={{ display: 'flex', gap: '6px', flexWrap: 'wrap' }}>
                  <button type="button" className="btn" style={{ fontSize: '12px', padding: '4px 8px' }} onClick={() => moveStep(idx, -1)}>
                    ↑
                  </button>
                  <button type="button" className="btn" style={{ fontSize: '12px', padding: '4px 8px' }} onClick={() => moveStep(idx, 1)}>
                    ↓
                  </button>
                  <button type="button" className="btn" style={{ fontSize: '12px', padding: '4px 8px' }} onClick={() => removeStep(idx)}>
                    Entfernen
                  </button>
                </div>
              </div>
            ))}
          </div>
          <div className="form-row">
            <label className="form-label">Notiz für Kanten (Fallback, optional)</label>
            <textarea
              className="form-input"
              rows={2}
              value={segmentNotes}
              onChange={(e) => setSegmentNotes(e.target.value)}
              placeholder="Wird pro Kante genutzt, wenn keine KI-Begründung vorliegt."
            />
          </div>
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px' }}>
            <button
              type="button"
              className="btn btn-primary"
              disabled={disabled || saving || pathSteps.filter((s) => s.exerciseId).length < 2}
              onClick={savePathToGraph}
            >
              {saving ? 'Speichern …' : 'Pfad in Graph speichern'}
            </button>
            <button
              type="button"
              className="btn btn-secondary"
              disabled={loading || saving}
              onClick={() => {
                setPathSteps([])
                setTargetSummary(null)
                setSemanticBrief(null)
                setPathQa(null)
                setGapFillOffers([])
                setProgressionRoadmap(null)
              }}
            >
              Vorschlag verwerfen
            </button>
          </div>
        </>
      ) : null}

      <ExerciseAiQuickCreateModal
        open={quickCreateOpen}
        onClose={closeQuickCreate}
        searchLabel={activeOffer?.title_hint || goalQuery}
        title={quickTitle}
        onTitleChange={setQuickTitle}
        sketch={quickSketch}
        onSketchChange={setQuickSketch}
        focusAreaId={quickFocusAreaId}
        onFocusAreaChange={setQuickFocusAreaId}
        focusAreas={focusAreas}
        catalogsReady={focusAreas.length > 0}
        busy={quickSaving}
        error={quickAiError}
        onRunAi={runQuickCreateAiSuggest}
      />

      <ExerciseAiSuggestPreviewModal
        draft={quickCreateDraft}
        onDraftChange={setQuickCreateDraft}
        onDiscard={() => {
          setQuickCreateDraft(null)
          setActivePlanningContextLines([])
          if (activeOffer) setQuickCreateOpen(true)
        }}
        planningContextLines={activePlanningContextLines}
        onApply={applyQuickCreateDraft}
        focusAreas={focusAreas}
        skillsCatalog={skillsCatalog}
        dialogTitle="Pfad-Lücke — KI-Entwurf bearbeiten"
        hint="Texte anpassen, dann als Übung speichern und in den Pfad einfügen."
        applyLabel={quickSaving ? 'Wird angelegt …' : 'Anlegen und in Pfad einfügen'}
        applyDisabled={quickSaving}
        zIndex={2100}
      />
    </div>
  )
}
