from typing import List, Dict, Any, Optional from datetime import datetime from fastapi import APIRouter, HTTPException from pydantic import BaseModel from learning_units import ( LearningUnit, LearningUnitCreate, LearningUnitUpdate, list_learning_units, get_learning_unit, create_learning_unit, update_learning_unit, delete_learning_unit, ) router = APIRouter( prefix="/learning-units", tags=["learning-units"], ) # ---------- Payload-Modelle für das Frontend ---------- class LearningUnitCreatePayload(BaseModel): """ Payload so, wie er aus dem Frontend kommt: { "student": "...", "subject": "...", "title": "...", "grade": "7a" } """ student: Optional[str] = None subject: Optional[str] = None title: Optional[str] = None grade: Optional[str] = None class AttachWorksheetsPayload(BaseModel): worksheet_files: List[str] class RemoveWorksheetPayload(BaseModel): worksheet_file: str # ---------- Hilfsfunktion: Backend-Modell -> Frontend-Objekt ---------- def unit_to_frontend_dict(lu: LearningUnit) -> Dict[str, Any]: """ Wandelt eine LearningUnit in das Format um, das das Frontend erwartet. Wichtig sind: - id - label (sichtbarer Name) - meta (Untertitelzeile) - worksheet_files (Liste von Dateinamen) """ label = lu.title or "Lerneinheit" # Meta-Text: z.B. "Thema: Auge · Klasse: 7a · angelegt am 10.12.2025" meta_parts: List[str] = [] if lu.topic: meta_parts.append(f"Thema: {lu.topic}") if lu.grade_level: meta_parts.append(f"Klasse: {lu.grade_level}") created_str = lu.created_at.strftime("%d.%m.%Y") meta_parts.append(f"angelegt am {created_str}") meta = " · ".join(meta_parts) return { "id": lu.id, "label": label, "meta": meta, "title": lu.title, "topic": lu.topic, "grade_level": lu.grade_level, "language": lu.language, "status": lu.status, "worksheet_files": lu.worksheet_files, "created_at": lu.created_at.isoformat(), "updated_at": lu.updated_at.isoformat(), } # ---------- Endpunkte ---------- @router.get("/", response_model=List[Dict[str, Any]]) def api_list_learning_units(): """Alle Lerneinheiten für das Frontend auflisten.""" units = list_learning_units() return [unit_to_frontend_dict(u) for u in units] @router.post("/", response_model=Dict[str, Any]) def api_create_learning_unit(payload: LearningUnitCreatePayload): """ Neue Lerneinheit anlegen. Mapped das Frontend-Payload (student/subject/title/grade) auf das generische LearningUnit-Modell. """ # Mindestens eines der Felder muss gesetzt sein if not (payload.student or payload.subject or payload.title): raise HTTPException( status_code=400, detail="Bitte mindestens Schüler/in, Fach oder Thema angeben.", ) # Titel/Topic bestimmen # sichtbarer Titel: bevorzugt Thema (title), sonst Kombination if payload.title: title = payload.title else: parts = [] if payload.subject: parts.append(payload.subject) if payload.student: parts.append(payload.student) title = " – ".join(parts) if parts else "Lerneinheit" topic = payload.title or payload.subject or None grade_level = payload.grade or None lu_create = LearningUnitCreate( title=title, description=None, topic=topic, grade_level=grade_level, language="de", worksheet_files=[], status="raw", ) lu = create_learning_unit(lu_create) return unit_to_frontend_dict(lu) @router.post("/{unit_id}/attach-worksheets", response_model=Dict[str, Any]) def api_attach_worksheets(unit_id: str, payload: AttachWorksheetsPayload): """ Fügt der Lerneinheit eine oder mehrere Arbeitsblätter hinzu. """ lu = get_learning_unit(unit_id) if not lu: raise HTTPException(status_code=404, detail="Lerneinheit nicht gefunden.") files_to_add = [f for f in payload.worksheet_files if f not in lu.worksheet_files] if files_to_add: new_list = lu.worksheet_files + files_to_add update = LearningUnitUpdate(worksheet_files=new_list) lu = update_learning_unit(unit_id, update) if not lu: raise HTTPException(status_code=500, detail="Lerneinheit konnte nicht aktualisiert werden.") return unit_to_frontend_dict(lu) @router.post("/{unit_id}/remove-worksheet", response_model=Dict[str, Any]) def api_remove_worksheet(unit_id: str, payload: RemoveWorksheetPayload): """ Entfernt genau ein Arbeitsblatt aus der Lerneinheit. """ lu = get_learning_unit(unit_id) if not lu: raise HTTPException(status_code=404, detail="Lerneinheit nicht gefunden.") if payload.worksheet_file not in lu.worksheet_files: # Nichts zu tun, aber kein Fehler – einfach unverändert zurückgeben return unit_to_frontend_dict(lu) new_list = [f for f in lu.worksheet_files if f != payload.worksheet_file] update = LearningUnitUpdate(worksheet_files=new_list) lu = update_learning_unit(unit_id, update) if not lu: raise HTTPException(status_code=500, detail="Lerneinheit konnte nicht aktualisiert werden.") return unit_to_frontend_dict(lu) @router.delete("/{unit_id}") def api_delete_learning_unit(unit_id: str): """ Lerneinheit komplett löschen (aktuell vom Frontend noch nicht verwendet). """ ok = delete_learning_unit(unit_id) if not ok: raise HTTPException(status_code=404, detail="Lerneinheit nicht gefunden.") return {"status": "deleted", "id": unit_id}