<script setup>
import { computed, nextTick, onMounted, onUnmounted, ref } from 'vue'
import { chatBaustein, pruefeBaustein, fetchFrageMuster } from '../api.js'
import { usePruefSlot } from '../pruefungCache.js'
import { renderMarkdown, renderMarkdownInline } from '../markdown.js'
import { useChat, istUnten } from '../composables/useChat.js'

const props = defineProps({
  topic: { type: String, required: true },
  baustein: { type: String, required: true },
  section: { type: String, default: '' },          // ausführliche Fassung
  sectionKompakt: { type: String, default: '' },   // kompakte Fassung (Merksätze) — Prüfungs-/Chat-Kontext
  provider: { type: String, default: 'claude' },
  status: { type: Object, default: null }, // {gute_antworten, streak, absolviert, verstanden, gemeistert}
  cap: { type: Number, default: 6 }, // Score-Deckel = Max des höchsten Formats (6/12/18/30)
  // 'trigger' (Liste): nur Tab-Leiste, Klick öffnet den Vollbild-Fokus.
  // 'full' (Fokus): Tabs + Panel-Inhalt wie gehabt.
  mode: { type: String, default: 'trigger' },
  initialTab: { type: String, default: null },
  ansicht: { type: String, default: 'kompakt' },   // kompakt | erklärend — steuert die linke Guide-Spalte
})

const emit = defineEmits(['statusChanged', 'openFokus', 'setAnsicht'])

// Meilensteine (Score-Bänder): Quiz→6, Lückentext→12, Erklären→18, FullGuide-Max 30.
const ABSOLVIERT = 6
const VERSTANDEN = 12
const GEMEISTERT = 18
const VOLL = 30
const st = computed(() => props.status || { gute_antworten: 0, streak: 0, absolviert: false, verstanden: false, gemeistert: false })
// Aktiver Modus aus Score-Band (unter 30 fix) + Schwierigkeit (ALT+E). Ab 30 frei.
// Ohne Frage-Muster (alter Baustein) gibt es nur Erklären — Quiz/Lückentext brauchen die Saat.
const MODI = ['quiz_leicht', 'quiz_schwer', 'lueck_leicht', 'lueck_schwer', 'erklaeren']
const score = computed(() => st.value.gute_antworten || 0)
const schwerWahl = ref(false)          // leicht/schwer in den Bändern unter 19 (ALT+E)
// Band aus einem Score: Lückentext ab 6, Erklären ab 12, Zufall ab 18 (Meilenstein-inklusiv).
function bandFuer(s) {
  if (s >= GEMEISTERT) return 'zufall'
  if (s >= VERSTANDEN) return 'erklaeren'
  if (s >= ABSOLVIERT) return 'lueckentext'
  return 'quiz'
}
// Am Format-Max: Score eingefroren („Max"). Gilt auch bei cap 30 (FullGuide, endgültig).
const amDeckel = computed(() => score.value >= props.cap)
// Aktuelles Band: am Deckel bleibt das Band des erreichten Formats (cap−1), sonst score-basiert.
// Ohne Frage-Muster (alter Baustein) gibt es nur Erklären.
const aktuellesBand = computed(() => musterModus.value ? bandFuer(amDeckel.value ? props.cap - 1 : score.value) : 'erklaeren')
// 'zufall' = Platzhalter; das gezogene Objekt trägt die echte Form/Schwierigkeit.
const aktiverModus = computed(() => {
  const b = aktuellesBand.value
  if (b === 'lueckentext') return schwerWahl.value ? 'lueck_schwer' : 'lueck_leicht'
  if (b === 'quiz') return schwerWahl.value ? 'quiz_schwer' : 'quiz_leicht'
  return b  // 'erklaeren' | 'zufall'
})
const imZufall = computed(() => aktuellesBand.value === 'zufall')
const aktiveForm = computed(() => {
  const m = aktiverModus.value
  if (m === 'zufall') return 'quiz'  // Platzhalter fürs idle-Widget; Objekt überschreibt
  return m.startsWith('quiz') ? 'quiz' : m.startsWith('lueck') ? 'lueckentext' : 'erklaeren'
})
const schwer = computed(() => aktiverModus.value.endsWith('_schwer'))
// Angezeigte Form: folgt der aktiven Form, friert aber ein, solange eine gezogene Frage
// sichtbar ist (sonst verschwindet das Ergebnis, wenn die Antwort eine Bandgrenze überschreitet).
const anzeigeForm = ref(null)
const zeigeForm = computed(() => anzeigeForm.value || aktiveForm.value)
// Band, in dem die gezeigte Frage gezogen wurde. Weicht es vom aktuellen Band ab, hat die
// letzte Antwort einen Meilenstein überschritten → Button „Zum nächsten Abschnitt".
const anzeigeBand = ref(null)
const abschnittWechsel = computed(() => anzeigeBand.value && anzeigeBand.value !== aktuellesBand.value)
// Schwierigkeit des gerade gezeigten Widgets (eingefroren) bzw. der aktiven Wahl.
const aktSchwer = computed(() => {
  if (zeigeForm.value === 'quiz' && quizAktuell.value) return quizAktuell.value.schwer
  if (zeigeForm.value === 'lueckentext' && lueckAktuell.value) return lueckAktuell.value.schwer
  return schwer.value
})
const modusRegel = computed(() => {
  const m = imZufall.value ? '−3' : '−1'  // Zufallband: Fehler kostet −3
  if (zeigeForm.value === 'quiz') return aktSchwer.value ? `x von 4 · +3/${m}` : `1 von 4 · +1/${m}`
  if (zeigeForm.value === 'lueckentext') return aktSchwer.value ? `frei tippen · +3/${m}` : `Begriff aus 4 · +1/${m}`
  return imZufall.value ? '+1/+2/+3 · Fehler −3' : '+1/+2/+3 · Nachfragen max +1 · schwach −1'
})
// Ende des aktuellen Bands (nächster Meilenstein).
const bandZiel = computed(() => {
  if (score.value >= GEMEISTERT) return VOLL
  if (score.value >= VERSTANDEN) return GEMEISTERT
  if (score.value >= ABSOLVIERT) return VERSTANDEN
  return ABSOLVIERT
})
const FORM_NAME = { quiz: 'Quiz', lueckentext: 'Lückentext', erklaeren: 'Erklären' }
const NAECHSTES_FORMAT = { 6: 'Guide', 12: 'ProGuide', 18: 'FullGuide' }

// --- Toggle-Bereich ---
const activeTab = ref(props.mode === 'full' ? props.initialTab : null) // null | 'chat' | 'pruefung'

// Klick auf einen Tab: in der Liste den Fokus öffnen, im Fokus den Tab umschalten.
function tabKlick(tab) {
  if (props.mode === 'trigger') { emit('openFokus', tab); return }
  activeTab.value = activeTab.value === tab ? null : tab
}

// --- Bausteinchat (flüchtig) ---
const chat = useChat((msgs) => chatBaustein({
  topic: props.topic, baustein: props.baustein, section: props.section, section_kompakt: props.sectionKompakt,
  messages: msgs, provider: props.provider,
}))

// --- Prüfung: gesteuerter Dialog ---
// Phasen: 'idle' (Frage anfordern) | 'frage_offen' (antworten/nachfragen) | 'bewertet' (diskutieren/neu bewerten/weiter)
// Durabler State liegt in einem GETEILTEN Slot pro Baustein (Modul-Store): überlebt
// das Remounten und eine spät eintreffende Frage ist sofort reaktiv sichtbar.
const pruefKey = `${props.topic}::${props.baustein}`
const slot = usePruefSlot(pruefKey)
const pruefMessages = slot.messages // {role, kind: 'frage'|'nachfrage'|'antwort'|'feedback'|'diskussion'|'fehler', content, bewertung?}
const pruefPhase = slot.phase
const aktuelleFrage = slot.aktuelleFrage      // ankert Bewertung/Diskussion
const letztesFeedback = slot.letztesFeedback  // Kontext für die Diskussion über eine Bewertung
const musterQuelle = slot.musterQuelle  // unveränderliche Voll-Liste der Frage-Muster (leer = Fallback)
const musterPool = slot.musterPool      // Arbeitskopie, ohne Zurücklegen; leer → Reset
const musterGeladen = slot.musterGeladen
const poolForm = slot.poolForm          // Form, für die der Pool gefüllt ist
const quizAktuell = slot.quizAktuell    // laufende Quiz-Frage (Widget-State)
const lueckAktuell = slot.lueckAktuell  // laufende Lückentext-Aufgabe (Widget-State)
// Transient (pro Instanz): Eingabe-Entwurf, Lade-Spinner.
const pruefInput = ref('')
const pruefLoading = ref(false)
const nachgefragt = ref(false)   // für die laufende Frage wurde nachgefragt → Gewinn max +1
const gruendlichMsg = ref(null)  // Feedback-Bubble, für die das Gründlich-Feld offen ist
const gruendlichText = ref('')   // optionale Begründung für „Gründlich prüfen"

const pruefMessagesEl = ref(null)
const pruefInputEl = ref(null)
const pruefStick = ref(true)     // nur auto-scrollen, wenn der Nutzer (fast) unten ist
let pruefRun = 0

function onPruefScroll() {
  if (pruefMessagesEl.value) pruefStick.value = istUnten(pruefMessagesEl.value)
}

function applyPruefung(res) {
  // res.streak nur bei antwort_pruefen gesetzt (verbindlich, persistiert); sonst Streak unverändert lassen.
  emit('statusChanged', { baustein: props.baustein, ...st.value, gute_antworten: res.gute_antworten, streak: res.streak ?? st.value.streak, absolviert: res.absolviert, verstanden: res.verstanden, gemeistert: res.gemeistert })
}

async function pruefScroll() {
  await nextTick()
  if (pruefMessagesEl.value && pruefStick.value) pruefMessagesEl.value.scrollTop = pruefMessagesEl.value.scrollHeight
}

// Nur echte Gesprächs-Turns ans Backend; Feedback bleibt reines UI-Artefakt.
function pruefDialog() {
  return pruefMessages.value
    .filter((m) => m.kind !== 'feedback' && m.kind !== 'fehler')
    .map((m) => ({ role: m.role, content: m.content }))
}

async function pruefSenden(payload, onOk) {
  const run = ++pruefRun
  pruefStick.value = true // eigene Aktion = ans Ende; Hochscrollen während des Wartens setzt es wieder false
  pruefLoading.value = true
  pruefScroll()
  try {
    const res = await pruefeBaustein({
      topic: props.topic, baustein: props.baustein, section: props.section, section_kompakt: props.sectionKompakt,
      provider: props.provider, messages: pruefDialog(), ...payload,
    })
    if (run !== pruefRun) return
    onOk(res)
    applyPruefung(res)
    pruefScroll()
    nextTick(() => pruefInputEl.value?.focus())
  } catch {
    if (run === pruefRun) pruefMessages.value.push({ role: 'assistant', kind: 'fehler', content: 'Hat nicht geklappt — bitte erneut.' })
  } finally {
    if (run === pruefRun) pruefLoading.value = false
  }
}

// Frage anzeigen (frisch oder vorgemerkt). Basis/Streak führt der Server je Frage.
function frageZeigen(text) {
  aktuelleFrage.value = text
  letztesFeedback.value = ''
  nachgefragt.value = false
  gruendlichMsg.value = null
  pruefMessages.value.push({ role: 'assistant', kind: 'frage', content: text })
  pruefPhase.value = 'frage_offen'
}

// Dedup: schon gestellte Fragen erkennen (Generator wiederholt sich auf kleinen Bausteinen).
function normFrage(t) { return (t || '').toLowerCase().replace(/\s+/g, ' ').trim() }
function gestellteFragen() {
  return new Set(pruefMessages.value.filter((m) => m.kind === 'frage').map((m) => normFrage(m.content)))
}

// --- Fragen-Pool: ZIEL vorformulierte Frage-OBJEKTE der aktiven Form (im Slot) ---
// Jedes Objekt: {form, frage, optionen?|satz?|loesung?|alternativen?}. Wechselt die
// aktive Form, wird der Pool geleert und für die neue Form neu gefüllt.
const POOL_ZIEL = 5
const pool = slot.pool
const inflight = slot.inflight
const pruefFehler = ref('')  // Fehlerhinweis für Quiz/Lückentext (kein Bubble-Verlauf)
let poolMiss = 0  // nur Fallback: aufeinanderfolgende Dubletten/Fehler — Cap gegen Endlosschleife

// Muster-Modus aktiv, sobald geladen und Muster vorhanden; sonst Fallback (nur Erklären).
const musterModus = computed(() => musterGeladen.value && musterQuelle.value.length > 0)

function objText(o) { return (o && (o.frage || o.satz)) || '' }

// Lückensatz rendern: an „___" splitten, Teile inline (mit $…$-Mathe), Lücke als Span.
// So bleibt die Lücke erhalten und Markdown fasst die Unterstriche nicht an.
function lueckSatzHtml(satz) {
  satz = String(satz || '')
  const m = satz.match(/_{3,}/)  // erste Lücke (drei oder mehr Unterstriche)
  if (!m) return renderMarkdownInline(satz)
  // Liegt die Lücke INNERHALB einer $…$-Formel (ungerade Zahl $ davor)? Dann nicht splitten
  // (das zerreißt die Formel) — stattdessen durch eine KaTeX-Linie ersetzen, Satz am Stück rendern.
  const inFormel = ((satz.slice(0, m.index).match(/\$/g) || []).length % 2) === 1
  if (inFormel) return renderMarkdownInline(satz.replace(/_{3,}/, '\\rule{2.5em}{0.4pt}'))
  // Lücke im Text: splitten + Lücken-Span.
  return satz.split(/_{3,}/).map((t) => renderMarkdownInline(t)).join('<span class="bp-luecke">______</span>')
}

function istBekannt(o) {
  const n = normFrage(objText(o))
  return !n || gestellteFragen().has(n) || pool.value.some((f) => normFrage(objText(f)) === n)
}

// Schon gestellte + vorgemerkte Fragen — nur Fallback-Modus (Erklären ohne Muster).
function vermeideListe() {
  const gestellt = pruefMessages.value.filter((m) => m.kind === 'frage').map((m) => m.content)
  return [...gestellt, ...pool.value.map(objText)]
}

// Muster-Sidecar einmal je Baustein laden (Slot-cached). Leer → Fallback.
async function musterLaden() {
  if (musterGeladen.value) return
  try {
    const res = await fetchFrageMuster(props.topic, props.baustein)
    musterQuelle.value = (res.muster || []).map((m) => (m.frage || '').trim()).filter(Boolean)
  } catch {
    musterQuelle.value = []
  }
  musterGeladen.value = true
}

function mischen(arr) {  // Fisher-Yates
  const a = [...arr]
  for (let i = a.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1))
    ;[a[i], a[j]] = [a[j], a[i]]
  }
  return a
}

// Ein Muster ohne Zurücklegen ziehen; Pool leer → Reset (neu mischen). null = Fallback.
function musterNehmen() {
  if (!musterQuelle.value.length) return null
  if (!musterPool.value.length) musterPool.value = mischen(musterQuelle.value)
  return musterPool.value.shift()
}

// Pool-Schlüssel = Form + Schwierigkeit; im Zufallband ein gemischter Pool ('zufall').
const poolKey = computed(() => imZufall.value ? 'zufall' : `${aktiveForm.value}/${schwer.value}`)

// Modus der nächsten Frage: im Zufallband (Score 19–30) zufällig aus allen 5 Modi.
function naechsterModus() {
  return imZufall.value ? MODI[Math.floor(Math.random() * MODI.length)] : aktiverModus.value
}

// Ein Frage-Objekt des aktiven Modus generieren (aus gezogener Saat; Erklären hat Fallback).
function frageEinzeln() {
  const modus = naechsterModus()
  const form = modus.startsWith('quiz') ? 'quiz' : modus.startsWith('lueck') ? 'lueckentext' : 'erklaeren'
  const istSchwer = modus.endsWith('_schwer')
  const muster = musterNehmen()
  const basis = {
    topic: props.topic, baustein: props.baustein, section: props.section,
    section_kompakt: props.sectionKompakt, provider: props.provider,
  }
  if (form === 'quiz' && muster) {
    return pruefeBaustein({ ...basis, aktion: 'quiz_frage', muster, schwer: istSchwer })
      .then((r) => ({ form, schwer: istSchwer, frage: r.frage, optionen: r.optionen }))
  }
  if (form === 'lueckentext' && muster) {
    return pruefeBaustein({ ...basis, aktion: 'lueck_frage', muster, schwer: istSchwer })
      .then((r) => istSchwer
        ? ({ form, schwer: true, frage: r.satz, satz: r.satz, loesung: r.loesung, alternativen: r.alternativen })
        : ({ form, schwer: false, frage: r.satz, satz: r.satz, optionen: r.optionen }))
  }
  if (muster) {  // erklaeren aus Muster
    return pruefeBaustein({ ...basis, aktion: 'frage', muster }).then((r) => ({ form: 'erklaeren', frage: r.frage }))
  }
  // Fallback (kein Muster-Sidecar): Erklären live mit Vermeide-Liste.
  return pruefeBaustein({ ...basis, aktion: 'frage', messages: pruefDialog(), vermeide: vermeideListe() })
    .then((r) => ({ form: 'erklaeren', frage: r.frage }))
}

// Pool leeren, wenn Form oder Schwierigkeit gewechselt hat (Bandgrenze oder ALT+E).
function poolFormPruefen() {
  if (poolForm.value !== poolKey.value) {
    pool.value = []
    poolForm.value = poolKey.value
    poolMiss = 0
  }
}

// Pool PARALLEL auffüllen: jeder zieht ein DISTINKTES Muster → keine Kollision.
function poolFuellen() {
  poolFormPruefen()
  const keyBeginn = poolKey.value
  const cap = musterModus.value ? Infinity : 3
  while (pool.value.length + inflight.value < POOL_ZIEL && poolMiss < cap) {
    inflight.value++
    frageEinzeln()
      .then((obj) => {
        if (obj && objText(obj) && poolKey.value === keyBeginn && (musterModus.value || !istBekannt(obj))) { pool.value.push(obj); poolMiss = 0 }
        else poolMiss++
      })
      .catch(() => { poolMiss++ })
      .finally(() => { inflight.value--; poolFuellen() })
  }
}

// Ein Frage-Objekt aus dem Pool nehmen; ist er leer, auf das erste eintreffende warten.
async function poolNehmen() {
  if (!pool.value.length) {
    const cap = musterModus.value ? Infinity : 3
    pruefLoading.value = true
    try {
      while (!pool.value.length && (inflight.value > 0 || poolMiss < cap)) {
        if (!inflight.value) poolFuellen()
        await new Promise((r) => setTimeout(r, 120))
      }
    } finally { pruefLoading.value = false }
  }
  return pool.value.length ? pool.value.shift() : null
}

// Ein gezogenes Objekt der passenden Form anzeigen (Erklären-Bubble bzw. Quiz/Lück-Widget).
function frageObjZeigen(obj) {
  pruefFehler.value = ''
  anzeigeForm.value = obj.form  // Anzeige an die gezogene Frage binden (Form einfrieren)
  anzeigeBand.value = aktuellesBand.value  // Band zum Zieh-Zeitpunkt (vor der Antwort)
  if (obj.form === 'quiz') {
    quizAktuell.value = { frage: obj.frage, optionen: obj.optionen, schwer: obj.schwer, gewaehlt: [], fertig: false, punkte: null, bewertung: null, feedback: '' }
  } else if (obj.form === 'lueckentext') {
    lueckAktuell.value = { satz: obj.satz, schwer: obj.schwer, optionen: obj.optionen || null, loesung: obj.loesung || '', alternativen: obj.alternativen || [], eingabe: '', gewaehlt: [], fertig: false, punkte: null, bewertung: null, feedback: '' }
    if (obj.schwer) nextTick(() => document.getElementById('bp-lueck-input')?.focus())
  } else {
    frageZeigen(obj.frage)
    nextTick(() => pruefInputEl.value?.focus())
  }
}

// Erste / nächste Frage: Muster laden, Pool füllen, schnellste zuerst zeigen.
async function naechsteFrageZeigen() {
  if (pruefLoading.value) return
  poolMiss = 0
  pruefFehler.value = ''
  await musterLaden()
  poolFuellen()
  const obj = await poolNehmen()
  if (obj) {
    frageObjZeigen(obj)
    pruefScroll()
  } else if (aktiveForm.value === 'erklaeren') {
    pruefMessages.value.push({ role: 'assistant', kind: 'fehler', content: 'Keine Frage — bitte erneut.' })
  } else {
    pruefFehler.value = 'Keine Frage — bitte erneut.'
  }
  poolFuellen()
}
const frageAnfordern = naechsteFrageZeigen

// Meilenstein überschritten: Einfrieren lösen (Ergebnis war sichtbar), ohne neue Frage zu
// ziehen → Leerlauf des neuen Bands („Frage anfordern").
function zumNaechstenAbschnitt() {
  anzeigeForm.value = null
  anzeigeBand.value = null
  quizAktuell.value = null
  lueckAktuell.value = null
  pruefMessages.value = []  // alten Erklären-Verlauf verwerfen (neuer Abschnitt)
  pruefPhase.value = 'idle'
  pruefFehler.value = ''
}

// --- Quiz: leicht = Single-Select (genau 1) · schwer = Multi-Select. Deterministisch. ---
function quizToggle(i) {
  const q = quizAktuell.value
  if (!q || q.fertig) return
  if (!q.schwer) { q.gewaehlt = q.gewaehlt.includes(i) ? [] : [i]; return }
  const idx = q.gewaehlt.indexOf(i)
  if (idx >= 0) q.gewaehlt.splice(idx, 1)
  else q.gewaehlt.push(i)
}

async function quizAntworten() {
  const q = quizAktuell.value
  if (!q || q.fertig || pruefLoading.value) return
  pruefLoading.value = true
  pruefFehler.value = ''
  try {
    const korrekt = q.optionen.map((o, i) => (o.korrekt ? i : -1)).filter((i) => i >= 0)
    const res = await pruefeBaustein({
      topic: props.topic, baustein: props.baustein, section: props.section, section_kompakt: props.sectionKompakt,
      provider: props.provider, aktion: 'quiz_antwort', frage: q.frage, cap: props.cap,
      auswahl: q.gewaehlt, korrekt, schwer: q.schwer,
    })
    q.fertig = true; q.punkte = res.punkte; q.bewertung = res.bewertung; q.feedback = res.feedback
    applyPruefung(res)
  } catch {
    pruefFehler.value = 'Hat nicht geklappt — bitte erneut.'
  } finally {
    pruefLoading.value = false
  }
}

// --- Lückentext: leicht = Begriff aus 4 (Single-Select) · schwer = frei tippen ---
function lueckToggle(i) {
  const l = lueckAktuell.value
  if (!l || l.fertig || l.schwer) return
  l.gewaehlt = l.gewaehlt.includes(i) ? [] : [i]
}

async function lueckAntworten() {
  const l = lueckAktuell.value
  if (!l || l.fertig || pruefLoading.value) return
  if (l.schwer ? !l.eingabe.trim() : !l.gewaehlt.length) return
  pruefLoading.value = true
  pruefFehler.value = ''
  try {
    const spez = l.schwer
      ? { schwer: true, loesung: l.loesung, alternativen: l.alternativen, eingabe: l.eingabe }
      : { schwer: false, auswahl: l.gewaehlt, korrekt: l.optionen.map((o, i) => (o.korrekt ? i : -1)).filter((i) => i >= 0) }
    const res = await pruefeBaustein({
      topic: props.topic, baustein: props.baustein, section: props.section, section_kompakt: props.sectionKompakt,
      provider: props.provider, aktion: 'lueck_antwort', frage: l.satz, cap: props.cap, ...spez,
    })
    l.fertig = true; l.punkte = res.punkte; l.bewertung = res.bewertung; l.feedback = res.feedback
    applyPruefung(res)
  } catch {
    pruefFehler.value = 'Hat nicht geklappt — bitte erneut.'
  } finally {
    pruefLoading.value = false
  }
}

function nachfragen() {
  const text = pruefInput.value.trim()
  if (!text || pruefLoading.value) return
  nachgefragt.value = true  // Hilfe genutzt → Gewinn für diese Frage max +1
  pruefMessages.value.push({ role: 'user', kind: 'nachfrage', content: text })
  pruefInput.value = ''
  pruefSenden(
    { aktion: 'diskussion', frage: aktuelleFrage.value, letzte_bewertung: letztesFeedback.value },
    (res) => pruefMessages.value.push({ role: 'assistant', kind: 'diskussion', content: res.reply }),
  )
}

let letzteFeedbackMsg = null // zuletzt gezeigte Bewertungs-Bubble
let pruefenRun = 0           // nur die jüngste Schnell-Bewertung darf anzeigen

function bewertungPayload() {
  return { frage: aktuelleFrage.value, cap: props.cap, nachgefragt: nachgefragt.value }
}

// Agent 1 (schnell): sofortiges Niveau + Punkte zeigen, dann Agent 2 (genau) im Hintergrund.
async function schnellBewerten() {
  const meine = ++pruefenRun
  pruefStick.value = true
  pruefLoading.value = true
  pruefScroll()
  try {
    const res = await pruefeBaustein({
      topic: props.topic, baustein: props.baustein, section: props.section, section_kompakt: props.sectionKompakt,
      provider: props.provider, messages: pruefDialog(), aktion: 'antwort', ...bewertungPayload(),
    })
    if (meine !== pruefenRun) return
    // Agent 1 ändert den Score NICHT — nur Feedback + voraussichtliche Punkte zeigen.
    letztesFeedback.value = res.feedback || ''
    pruefMessages.value.push({ role: 'assistant', kind: 'feedback', content: res.feedback || '', bewertung: res.bewertung, punkte: res.punkte, geprueft: false })
    letzteFeedbackMsg = pruefMessages.value[pruefMessages.value.length - 1]
    pruefPhase.value = 'bewertet'
    pruefScroll()
    nextTick(() => pruefInputEl.value?.focus())
    genauBewerten() // Agent 2 wertet verbindlich (setzt den Score)
  } catch {
    if (meine === pruefenRun) pruefMessages.value.push({ role: 'assistant', kind: 'fehler', content: 'Hat nicht geklappt — bitte erneut.' })
  } finally {
    if (meine === pruefenRun) pruefLoading.value = false
  }
}

// Agent 2 (genau): Bewerter + Kritiker. Korrigiert Bubble + Score (Server-Wahrheit, immer übernehmen).
// gruendlich=true: starkes Modell, optional mit Begründung des Lerners.
async function genauBewerten(gruendlich = false, begruendung = '') {
  const ziel = letzteFeedbackMsg
  if (gruendlich) pruefLoading.value = true
  try {
    const res = await pruefeBaustein({
      topic: props.topic, baustein: props.baustein, section: props.section, section_kompakt: props.sectionKompakt,
      provider: props.provider, messages: pruefDialog(), aktion: 'antwort_pruefen', ...bewertungPayload(), gruendlich, begruendung,
    })
    applyPruefung(res)
    if (ziel) {
      ziel.content = res.feedback || ziel.content
      ziel.bewertung = res.bewertung
      ziel.punkte = res.punkte
      ziel.geprueft = true
    }
  } catch {
    if (ziel) ziel.geprueft = true
  } finally {
    if (gruendlich) pruefLoading.value = false
  }
}

function antwortAbgeben() {
  const text = pruefInput.value.trim()
  if (!text || pruefLoading.value) return
  pruefMessages.value.push({ role: 'user', kind: 'antwort', content: text })
  pruefInput.value = ''
  schnellBewerten()
}

// Lief schon eine Diskussion? Dann darf der Verlauf direkt bewertet werden.
const hatDiskussion = computed(() => pruefMessages.value.some((m) => m.kind === 'nachfrage' || m.kind === 'diskussion'))

// „Verlauf bewerten": den bisherigen Dialog als Antwort werten (Feld wird ignoriert).
function verlaufBewerten() {
  if (pruefLoading.value) return
  schnellBewerten()
}

// Rechtsklick auf eine Bewertung → Gründlich-Feld öffnen; Absenden re-bewertet (mit Begründung).
function gruendlichOeffnen(msg) {
  gruendlichText.value = ''
  gruendlichMsg.value = msg
  nextTick(() => document.getElementById('bp-gruendlich-input')?.focus())
}
function gruendlichAbsenden() {
  if (pruefLoading.value) return
  letzteFeedbackMsg = gruendlichMsg.value || letzteFeedbackMsg
  const text = gruendlichText.value.trim()
  gruendlichMsg.value = null
  genauBewerten(true, text)
}

function punkteLabel(p) {
  if (p == null) return ''
  return p > 0 ? `+${p}` : p < 0 ? String(p) : '±0'
}

// Abbruch wie im Chat: Run-Counter hochzählen → laufendes Ergebnis (pruefSenden
// und schnellBewerten) wird verworfen, Buttons sofort frei. Agent läuft serverseitig aus.
function pruefAbbrechen() {
  if (!pruefLoading.value) return
  pruefRun++
  pruefenRun++
  pruefLoading.value = false
  pruefMessages.value.push({ role: 'assistant', kind: 'fehler', content: 'Abgebrochen.' })
}

// ESC bricht ab — window-Listener, da nach Button-Klick der Fokus das Panel verlässt.
function onWindowKey(e) {
  if (e.key === 'Escape' && pruefLoading.value) { e.preventDefault(); pruefAbbrechen() }
}
onMounted(() => {
  if (props.mode !== 'full') return  // Trigger-Modus (Liste): nur Tab-Leiste, keine Prüfungs-/Text-Logik
  window.addEventListener('keydown', onWindowKey)
  window.addEventListener('keydown', onPruefKey)
  musterLaden()  // GET (kein Agent) — setzt die aktive Form früh korrekt (Quiz/Lückentext/Erklären)
})
onUnmounted(() => {
  window.removeEventListener('keydown', onWindowKey)
  window.removeEventListener('keydown', onPruefKey)
})

// ALT+E: leicht↔schwer der Form (Quiz/Lückentext). Im Erklären- und Zufallband ohne Wirkung.
function variantWechseln() {
  if (imZufall.value) return
  if (aktiveForm.value !== 'quiz' && aktiveForm.value !== 'lueckentext') return
  schwerWahl.value = !schwerWahl.value
  // Einfrieren + altes Widget verwerfen → frische Frage der neuen Variante anfordern.
  anzeigeForm.value = null
  anzeigeBand.value = null
  quizAktuell.value = null
  lueckAktuell.value = null
}

// Quiz / Lückentext-Auswahl ist ein Wahl-Widget mit 1–4-Tasten; sonst Textfeld/Bubble.
const wahlWidget = computed(() => {
  if (zeigeForm.value === 'quiz') return quizAktuell.value
  if (zeigeForm.value === 'lueckentext' && lueckAktuell.value && !lueckAktuell.value.schwer) return lueckAktuell.value
  return null
})
// Eingabefeld der aktuellen Form (Lückentext frei / Erklären) — für „Alt fokussiert".
function eingabeFeld() {
  if (zeigeForm.value === 'lueckentext' && lueckAktuell.value && lueckAktuell.value.schwer && !lueckAktuell.value.fertig) {
    return document.getElementById('bp-lueck-input')
  }
  if (zeigeForm.value === 'erklaeren' && pruefPhase.value === 'frage_offen') return pruefInputEl.value
  return null
}
// Nach einer Antwort: bei Meilenstein-Überschreitung in den neuen Abschnitt, sonst nächste Frage.
function weiterAktion() {
  if (abschnittWechsel.value) zumNaechstenAbschnitt()
  else naechsteFrageZeigen()
}
// Primäre Aktion je Form: keine Frage → anfordern · offen → antworten · fertig → weiter.
function primaerAktion() {
  if (pruefLoading.value) return
  const f = zeigeForm.value
  if (f === 'quiz') { if (!quizAktuell.value) frageAnfordern(); else if (!quizAktuell.value.fertig) quizAntworten(); else weiterAktion(); return }
  if (f === 'lueckentext') { if (!lueckAktuell.value) frageAnfordern(); else if (!lueckAktuell.value.fertig) lueckAntworten(); else weiterAktion(); return }
  if (pruefPhase.value === 'idle') frageAnfordern()
  else if (pruefPhase.value === 'frage_offen') { if (pruefInput.value.trim()) antwortAbgeben() }
  else weiterAktion()
}

// 1–4 (nackt): Option im Wahl-Widget toggeln. Alt allein: ins Eingabefeld springen.
// Alt+2 primär (antworten/nächste) · Alt+Q Ansicht · Alt+E Variante · Alt+1/3 Erklären.
function onPruefKey(e) {
  if (e.repeat) return
  if (props.mode !== 'full' || activeTab.value !== 'pruefung') return
  // Alt allein → ins Eingabefeld (Lückentext frei / Erklären), wie bei Frage-Antwort.
  if (e.key === 'Alt') {
    const el = eingabeFeld()
    if (el) { e.preventDefault(); el.focus() }
    return
  }
  if (!e.altKey) {
    // Nackte 1–4: Wahl-Widget toggeln — aber nicht, während ein Textfeld den Fokus hat.
    if (['1', '2', '3', '4'].includes(e.key) && wahlWidget.value && !wahlWidget.value.fertig) {
      const ae = document.activeElement
      if (ae && (ae.tagName === 'INPUT' || ae.tagName === 'TEXTAREA')) return
      e.preventDefault()
      const i = Number(e.key) - 1
      if (i < wahlWidget.value.optionen.length) (zeigeForm.value === 'quiz' ? quizToggle : lueckToggle)(i)
    }
    return
  }
  if (e.code === 'KeyQ') {
    e.preventDefault()
    const r = ['kompakt', 'erklärend', 'grafik']
    emit('setAnsicht', r[(r.indexOf(props.ansicht) + 1) % 3])
    return
  }
  if (e.code === 'KeyE') { e.preventDefault(); variantWechseln(); return }
  if (e.key === '2') { e.preventDefault(); primaerAktion(); return }
  // Erklären-Sondertasten
  if (e.key === '1') { e.preventDefault(); if (zeigeForm.value === 'erklaeren' && pruefPhase.value === 'frage_offen' && pruefInput.value.trim()) nachfragen(); return }
  if (e.key === '3') { e.preventDefault(); if (zeigeForm.value === 'erklaeren' && pruefPhase.value === 'frage_offen' && hatDiskussion.value) verlaufBewerten() }
}
</script>

<template>
  <div class="bp">
    <div class="bp-toggles">
      <!-- Ansicht-Umschalter (nur Vollbild): steuert die linke Guide-Spalte, links vor den Tabs -->
      <div v-if="mode === 'full'" class="bp-ansicht">
        <button :class="{ active: ansicht === 'kompakt' }" title="Merksätze" @click="emit('setAnsicht', 'kompakt')">Kompakt</button>
        <button :class="{ active: ansicht === 'erklärend' }" title="Ausführliche Erklärung" @click="emit('setAnsicht', 'erklärend')">Erklärend</button>
        <button :class="{ active: ansicht === 'grafik' }" title="Diagramm" @click="emit('setAnsicht', 'grafik')">Grafik</button>
      </div>
      <button :class="{ active: activeTab === 'chat' }" @click="tabKlick('chat')">
        Chat
      </button>
      <button :class="{ active: activeTab === 'pruefung' }" @click="tabKlick('pruefung')">
        Prüfung
        <span v-if="st.gemeistert" class="bp-chip gold" :title="`Gemeistert (${GEMEISTERT})`">✓✓✓ {{ score }}/{{ cap }}</span>
        <span v-else-if="st.verstanden" class="bp-chip lila" :title="`Verstanden (${VERSTANDEN})`">✓✓ {{ score }}/{{ cap }}</span>
        <span v-else-if="st.absolviert" class="bp-chip done" :title="`Absolviert (${ABSOLVIERT})`">✓ {{ score }}/{{ cap }}</span>
        <span v-else-if="score" class="bp-chip">{{ score }}/{{ cap }}</span>
      </button>
    </div>

    <div v-if="mode === 'full' && activeTab" class="bp-panel">
      <!-- Bausteinchat -->
      <div v-if="activeTab === 'chat'">
        <div :ref="chat.messagesEl" class="bp-messages" @scroll="chat.onScroll">
          <p v-if="!chat.messages.value.length" class="bp-hint">Frag etwas zu diesem Baustein. Der Verlauf wird nicht gespeichert.</p>
          <template v-for="(m, i) in chat.messages.value" :key="i">
            <div v-if="m.role === 'assistant'" class="bp-msg assistant markdown" v-html="renderMarkdown(m.content)"></div>
            <div v-else class="bp-msg user">{{ m.content }}</div>
          </template>
          <div v-if="chat.loading.value" class="bp-msg assistant bp-typing">Denkt…</div>
        </div>
        <div class="bp-input">
          <textarea
            :ref="chat.inputEl"
            v-model="chat.input.value"
            rows="2"
            placeholder="Frage zum Baustein…"
            @keydown.enter.exact.prevent="chat.send"
          ></textarea>
          <button :disabled="!chat.input.value.trim() && !chat.loading.value" :class="{ cancel: chat.loading.value }" @click="chat.send">
            {{ chat.loading.value ? '✕' : '➤' }}
          </button>
        </div>
      </div>

      <!-- Prüfung: gesteuerter Dialog -->
      <div v-else>
        <p class="bp-hint">
          <template v-if="amDeckel">{{ FORM_NAME[zeigeForm] }} · {{ score }}/{{ cap }} — <strong>Max</strong>.<template v-if="cap < VOLL"> Erstelle den {{ NAECHSTES_FORMAT[cap] }} für mehr.</template></template>
          <template v-else>{{ FORM_NAME[zeigeForm] }} · {{ score }}/{{ bandZiel }} · {{ modusRegel }}<span v-if="imZufall" class="bp-hint-key"> · zufällig</span></template>
        </p>
        <button
          v-if="!amDeckel && !imZufall && zeigeForm !== 'erklaeren'"
          class="bp-variant"
          title="Alt+E"
          @click="variantWechseln"
        >{{ aktSchwer ? 'Schwer' : 'Leicht' }} · wechseln</button>

        <!-- Quiz: Frage + Mehrfachauswahl (Widget bleibt auch am Deckel — Üben ohne Punkte) -->
        <template v-if="zeigeForm === 'quiz'">
          <div v-if="!quizAktuell" class="bp-actions">
            <button v-if="pruefLoading" class="bp-action cancel" title="ESC" @click="pruefAbbrechen">Abbrechen</button>
            <button v-else class="bp-action primary" @click="frageAnfordern">Frage anfordern</button>
          </div>
          <div v-else class="bp-quiz">
            <p class="bp-quiz-frage markdown" v-html="renderMarkdownInline(quizAktuell.frage)"></p>
            <div class="bp-quiz-grid">
              <button
                v-for="(o, i) in quizAktuell.optionen" :key="i"
                type="button"
                class="bp-quiz-opt"
                :class="{ gewaehlt: quizAktuell.gewaehlt.includes(i), richtig: quizAktuell.fertig && o.korrekt, falsch: quizAktuell.fertig && !o.korrekt && quizAktuell.gewaehlt.includes(i) }"
                :disabled="quizAktuell.fertig"
                :title="`${i + 1}`"
                @click="quizToggle(i)"
              >
                <span class="markdown" v-html="renderMarkdownInline(o.text)"></span>
              </button>
            </div>
            <p v-if="pruefFehler" class="bp-error">{{ pruefFehler }}</p>
            <div class="bp-actions">
              <button v-if="!quizAktuell.fertig" class="bp-action primary" title="Alt+2" :disabled="pruefLoading" @click="quizAntworten">Antworten</button>
              <template v-else>
                <span class="bp-niveau" :class="quizAktuell.bewertung">{{ punkteLabel(quizAktuell.punkte) }}</span>
                <span class="bp-form-feedback">{{ quizAktuell.feedback }}</span>
                <button v-if="abschnittWechsel" class="bp-action primary" @click="zumNaechstenAbschnitt">Zum nächsten Abschnitt</button>
                <button v-else class="bp-action primary" @click="naechsteFrageZeigen">Nächste</button>
              </template>
            </div>
          </div>
        </template>

        <!-- Lückentext: Satz mit Lücke + Eingabe -->
        <template v-else-if="zeigeForm === 'lueckentext'">
          <div v-if="!lueckAktuell" class="bp-actions">
            <button v-if="pruefLoading" class="bp-action cancel" title="ESC" @click="pruefAbbrechen">Abbrechen</button>
            <button v-else class="bp-action primary" @click="frageAnfordern">Frage anfordern</button>
          </div>
          <div v-else class="bp-lueck">
            <p class="bp-lueck-satz markdown" v-html="lueckSatzHtml(lueckAktuell.satz)"></p>
            <!-- schwer: frei tippen -->
            <input
              v-if="lueckAktuell.schwer"
              id="bp-lueck-input"
              v-model="lueckAktuell.eingabe"
              :disabled="lueckAktuell.fertig"
              placeholder="Begriff für die Lücke…"
              @keyup.enter="lueckAntworten"
            />
            <p v-if="lueckAktuell.schwer && lueckAktuell.fertig && !lueckAktuell.feedback.startsWith('Richtig')" class="bp-lueck-loesung">Lösung: <span class="markdown" v-html="renderMarkdownInline(lueckAktuell.loesung)"></span></p>
            <!-- leicht: Begriff aus 4 wählen -->
            <div v-if="!lueckAktuell.schwer" class="bp-quiz-grid">
              <button
                v-for="(o, i) in lueckAktuell.optionen" :key="i"
                type="button"
                class="bp-quiz-opt"
                :class="{ gewaehlt: lueckAktuell.gewaehlt.includes(i), richtig: lueckAktuell.fertig && o.korrekt, falsch: lueckAktuell.fertig && !o.korrekt && lueckAktuell.gewaehlt.includes(i) }"
                :disabled="lueckAktuell.fertig"
                :title="`${i + 1}`"
                @click="lueckToggle(i)"
              >
                <span class="markdown" v-html="renderMarkdownInline(o.text)"></span>
              </button>
            </div>
            <p v-if="pruefFehler" class="bp-error">{{ pruefFehler }}</p>
            <div class="bp-actions">
              <button v-if="!lueckAktuell.fertig" class="bp-action primary" title="Alt+2" :disabled="pruefLoading || (lueckAktuell.schwer ? !lueckAktuell.eingabe.trim() : !lueckAktuell.gewaehlt.length)" @click="lueckAntworten">Antworten</button>
              <template v-else>
                <span class="bp-niveau" :class="lueckAktuell.bewertung">{{ punkteLabel(lueckAktuell.punkte) }}</span>
                <span class="bp-form-feedback">{{ lueckAktuell.feedback }}</span>
                <button v-if="abschnittWechsel" class="bp-action primary" @click="zumNaechstenAbschnitt">Zum nächsten Abschnitt</button>
                <button v-else class="bp-action primary" @click="naechsteFrageZeigen">Nächste</button>
              </template>
            </div>
          </div>
        </template>

        <!-- Erklären: gesteuerter Dialog (bestehend) -->
        <template v-else>
          <div v-if="pruefMessages.length" ref="pruefMessagesEl" class="bp-messages" @scroll="onPruefScroll">
            <template v-for="(m, i) in pruefMessages" :key="i">
              <div v-if="m.kind === 'feedback'" class="bp-feedback" :class="m.bewertung" title="Klick: gründlich prüfen" @click="gruendlichOeffnen(m)">
                <span v-if="m.punkte != null" class="bp-niveau">{{ punkteLabel(m.punkte) }}</span>{{ m.content }}<span v-if="!m.geprueft" class="bp-pruefend"> · wird geprüft…</span>
                <div v-if="gruendlichMsg === m" class="bp-gruendlich" @click.stop>
                  <input id="bp-gruendlich-input" v-model="gruendlichText" placeholder="Warum unzufrieden? (optional)" @keyup.enter="gruendlichAbsenden" />
                  <button class="bp-action primary" @click="gruendlichAbsenden">Gründlich prüfen</button>
                  <button class="bp-action" @click="gruendlichMsg = null">×</button>
                </div>
              </div>
              <div v-else-if="m.kind === 'fehler'" class="bp-error">{{ m.content }}</div>
              <div v-else-if="m.role === 'assistant'" class="bp-msg assistant markdown" v-html="renderMarkdown(m.content)"></div>
              <div v-else class="bp-msg user">{{ m.content }}</div>
            </template>
            <div v-if="pruefLoading" class="bp-msg assistant bp-typing">…</div>
          </div>

          <div v-if="pruefPhase === 'idle'" class="bp-actions">
            <button v-if="pruefLoading" class="bp-action cancel" title="ESC" @click="pruefAbbrechen">Abbrechen</button>
            <button v-else class="bp-action primary" @click="frageAnfordern">Frage anfordern</button>
          </div>

          <template v-else>
            <div v-if="pruefPhase === 'frage_offen'" class="bp-input">
              <textarea
                ref="pruefInputEl"
                v-model="pruefInput"
                rows="2"
                placeholder="Antwort — oder Nachfrage bei Unklarheit…"
              ></textarea>
            </div>
            <div class="bp-actions">
              <button v-if="pruefLoading" class="bp-action cancel" title="ESC" @click="pruefAbbrechen">Abbrechen</button>
              <template v-else-if="pruefPhase === 'frage_offen'">
                <button class="bp-action" title="Alt+1" :disabled="!pruefInput.trim()" @click="nachfragen"><span class="bp-kbd">1</span>Nachfragen</button>
                <button class="bp-action primary" title="Alt+2" :disabled="!pruefInput.trim()" @click="antwortAbgeben"><span class="bp-kbd">2</span>Antwort abgeben</button>
                <button v-if="hatDiskussion" class="bp-action" title="Alt+3" @click="verlaufBewerten"><span class="bp-kbd">3</span>Verlauf bewerten</button>
              </template>
              <template v-else>
                <button v-if="abschnittWechsel" class="bp-action primary" title="Alt+2" @click="zumNaechstenAbschnitt"><span class="bp-kbd">2</span>Zum nächsten Abschnitt</button>
                <button v-else class="bp-action primary" title="Alt+2" @click="naechsteFrageZeigen"><span class="bp-kbd">2</span>Nächste Frage</button>
              </template>
            </div>
          </template>
        </template>
      </div>
    </div>
  </div>
</template>

<style scoped>
.bp { margin-top: 0.75rem; }

.bp-toggles { display: flex; gap: 0.4rem; }
.bp-toggles button {
  display: inline-flex; align-items: center; gap: 0.35rem;
  padding: 0.25rem 0.7rem;
  font-size: 0.8rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--panel-soft);
  color: var(--text-muted);
  cursor: pointer;
}
.bp-toggles button:hover { border-color: var(--border-strong); color: var(--text); }
.bp-toggles button.active { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }

/* Ansicht-Umschalter (Kompakt/Erklärend/Grafik) — segmentiert, links vor den Tabs */
.bp-ansicht { display: inline-flex; margin-right: 0.5rem; }
.bp-ansicht button {
  padding: 0.25rem 0.6rem;
  font-size: 0.75rem;
  border: 1px solid var(--border);
  background: var(--panel-soft);
  color: var(--text-muted);
  cursor: pointer;
}
.bp-ansicht button:first-child { border-radius: 999px 0 0 999px; }
.bp-ansicht button:last-child { border-radius: 0 999px 999px 0; }
.bp-ansicht button + button { border-left: none; }
.bp-ansicht button:hover { color: var(--text); }
.bp-ansicht button.active { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }

/* Schwierigkeits-Umschalter (Alt+E) — eigener Button, mobil tippbar */
.bp-variant {
  margin: 0 0 0.6rem;
  padding: 0.2rem 0.7rem;
  font-size: 0.72rem;
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  background: var(--panel-soft);
  color: var(--text-muted);
  cursor: pointer;
}
.bp-variant:hover { border-color: var(--accent); color: var(--text); }

.bp-chip {
  font-size: 0.7rem;
  padding: 0 0.35rem;
  border-radius: 999px;
  background: var(--panel);
  border: 1px solid var(--border);
  color: var(--text-muted);
}
.bp-chip.done { background: var(--success-soft); border-color: var(--success-border); color: var(--success); }
.bp-chip.lila { background: color-mix(in srgb, #8b5cf6 16%, var(--panel)); border-color: #8b5cf6; color: #6d28d9; }
.bp-chip.gold { background: color-mix(in srgb, #d4af37 20%, var(--panel)); border-color: #d4af37; color: #8a6d12; }

.bp-panel {
  margin-top: 0.6rem;
  padding: 0.75rem 0.9rem;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--panel-soft);
}

.bp-hint { font-size: 0.85rem; color: var(--text-muted); margin: 0 0 0.5rem; }
.bp-hint-key { font-size: 0.72rem; opacity: 0.7; white-space: nowrap; }
.bp-error { font-size: 0.85rem; color: var(--danger); margin: 0.5rem 0 0; }

.bp-action {
  margin-top: 0.5rem;
  padding: 0.3rem 0.8rem;
  font-size: 0.8rem;
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  background: var(--panel);
  color: var(--text);
  cursor: pointer;
}
.bp-action:hover { border-color: var(--accent); }
.bp-action:disabled { opacity: 0.5; cursor: default; }
.bp-action.primary { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.bp-action.primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); }
.bp-action.cancel { background: var(--danger); border-color: var(--danger); color: var(--on-accent); }

.bp-actions { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: 0.5rem; }
.bp-actions .bp-action { margin-top: 0; }

.bp-kbd {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 1rem; height: 1rem; padding: 0 0.2rem; margin-right: 0.35rem;
  font-size: 0.65rem; font-weight: 600; border-radius: 3px;
  background: var(--panel); border: 1px solid var(--border); color: var(--text-muted);
}
.bp-action.primary .bp-kbd { background: color-mix(in srgb, var(--on-accent) 20%, transparent); border-color: transparent; color: var(--on-accent); }

.bp-messages { display: flex; flex-direction: column; gap: 0.4rem; max-height: 320px; overflow-y: auto; }
.bp-msg {
  max-width: 88%;
  padding: 0.4rem 0.65rem;
  border-radius: 10px;
  font-size: 0.88rem;
  line-height: 1.45;
  overflow-wrap: anywhere;
}
.bp-msg.user { align-self: flex-end; background: var(--accent); color: var(--on-accent); white-space: pre-wrap; }
.bp-msg.assistant { align-self: flex-start; background: var(--panel); border: 1px solid var(--border); }
.bp-typing { color: var(--text-faint); font-style: italic; }

/* Bewertung der letzten Antwort — getrennt über der nächsten Frage */
.bp-feedback {
  align-self: flex-start;
  max-width: 88%;
  padding: 0.3rem 0.6rem;
  border-radius: 8px;
  font-size: 0.82rem;
  line-height: 1.4;
  border: 1px solid var(--border);
}
.bp-pruefend { font-style: italic; opacity: 0.7; font-size: 0.92em; }
.bp-feedback { cursor: pointer; }
.bp-feedback.gut { background: var(--success-soft); border-color: var(--success-border); color: var(--success); }
.bp-feedback.neutral { background: var(--warning-soft); border-color: var(--warning-border); color: var(--warning); }
.bp-feedback.schlecht { background: var(--danger-soft, #fee2e2); border-color: var(--danger-border, #f87171); color: var(--danger); }
.bp-niveau { font-weight: 700; text-transform: uppercase; font-size: 0.62rem; letter-spacing: 0.03em; margin-right: 0.4rem; opacity: 0.85; }
.bp-niveau.gut { color: var(--success); }
.bp-niveau.neutral { color: var(--warning); }
.bp-niveau.schlecht { color: var(--danger); }

/* Quiz: Frage + Mehrfachauswahl */
.bp-quiz, .bp-lueck { margin-top: 0.6rem; }
.bp-quiz-frage, .bp-lueck-satz { font-size: 0.9rem; font-weight: 600; margin: 0 0 0.5rem; line-height: 1.5; }
.bp-luecke { font-weight: 700; letter-spacing: 1px; color: var(--accent); padding: 0 0.15rem; }
.bp-quiz-opt .markdown, .bp-quiz-frage.markdown, .bp-lueck-satz.markdown { display: inline; }
.bp-quiz-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem; margin-bottom: 0.5rem; }
.bp-quiz-opt {
  display: flex; gap: 0.45rem; align-items: flex-start; text-align: left;
  padding: 0.5rem 0.6rem;
  border: 1px solid var(--border); border-radius: 8px;
  background: var(--panel); color: var(--text); cursor: pointer; font-size: 0.85rem;
}
.bp-quiz-opt:disabled { cursor: default; }
.bp-quiz-opt.gewaehlt { border-color: var(--accent); background: var(--accent-soft, rgba(99, 102, 241, 0.12)); }
.bp-quiz-opt.richtig { background: var(--success-soft); border-color: var(--success-border); }
.bp-quiz-opt.falsch { background: var(--danger-soft, #fee2e2); border-color: var(--danger-border, #f87171); }
.bp-form-feedback { font-size: 0.82rem; color: var(--text-muted); flex: 1; }

/* Lückentext: Satz + Eingabe */
.bp-lueck input {
  width: 100%; box-sizing: border-box; padding: 0.45rem 0.6rem; font: inherit; font-size: 0.88rem;
  border: 1px solid var(--border); border-radius: 8px; background: var(--panel); color: var(--text);
}
.bp-lueck input:disabled { opacity: 0.7; }
.bp-lueck-loesung { font-size: 0.82rem; color: var(--success); margin: 0.35rem 0 0; }
/* Gründlich-prüfen-Feld (per Rechtsklick) innerhalb der Bewertungs-Bubble */
.bp-gruendlich { display: flex; gap: 0.3rem; margin-top: 0.4rem; align-items: center; }
.bp-gruendlich input {
  flex: 1; min-width: 0; padding: 0.3rem 0.5rem; font: inherit; font-size: 0.8rem;
  border: 1px solid var(--border-strong); border-radius: 6px; background: var(--panel); color: var(--text);
}
.bp-gruendlich .bp-action { margin-top: 0; }

.bp-input { display: flex; gap: 0.4rem; margin-top: 0.55rem; align-items: flex-end; }
.bp-input textarea {
  flex: 1;
  resize: none;
  padding: 0.45rem 0.6rem;
  font: inherit;
  font-size: 0.88rem;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--panel);
  color: var(--text);
}
.bp-input button {
  padding: 0.45rem 0.7rem;
  border: none;
  border-radius: 8px;
  background: var(--accent);
  color: var(--on-accent);
  cursor: pointer;
}
.bp-input button:disabled { opacity: 0.5; cursor: default; }
.bp-input button.cancel { background: var(--danger); }
</style>
