""" Classroom API - Session Actions Routes Quick actions (pause, extend, timer), suggestions, utility endpoints. """ from typing import Dict, Optional, Any from datetime import datetime import logging from fastapi import APIRouter, HTTPException, Query from sqlalchemy import text from classroom_engine import ( LessonPhase, LessonStateMachine, PhaseTimer, SuggestionEngine, LESSON_PHASES, ) from ..models import ( ExtendTimeRequest, TimerStatus, SuggestionItem, SuggestionsResponse, PhasesListResponse, ActiveSessionsResponse, ) from ..services.persistence import ( sessions, persist_session, get_session_or_404, DB_ENABLED, SessionLocal, ) from .sessions_core import build_session_response, SessionResponse logger = logging.getLogger(__name__) router = APIRouter(tags=["Sessions"]) # === Quick Actions (Feature f26/f27/f28) === @router.post("/sessions/{session_id}/pause", response_model=SessionResponse) async def toggle_pause(session_id: str) -> SessionResponse: """Pausiert oder setzt die laufende Stunde fort (Feature f27).""" session = get_session_or_404(session_id) if session.current_phase in [LessonPhase.NOT_STARTED, LessonPhase.ENDED]: raise HTTPException(status_code=400, detail="Stunde ist nicht aktiv") if session.is_paused: if session.pause_started_at: pause_duration = (datetime.utcnow() - session.pause_started_at).total_seconds() session.total_paused_seconds += int(pause_duration) session.is_paused = False session.pause_started_at = None else: session.is_paused = True session.pause_started_at = datetime.utcnow() persist_session(session) return build_session_response(session) @router.post("/sessions/{session_id}/extend", response_model=SessionResponse) async def extend_phase(session_id: str, request: ExtendTimeRequest) -> SessionResponse: """Verlaengert die aktuelle Phase um zusaetzliche Minuten (Feature f28).""" session = get_session_or_404(session_id) if session.current_phase in [LessonPhase.NOT_STARTED, LessonPhase.ENDED]: raise HTTPException(status_code=400, detail="Stunde ist nicht aktiv") phase_id = session.current_phase.value current_duration = session.phase_durations.get(phase_id, 10) session.phase_durations[phase_id] = current_duration + request.minutes persist_session(session) return build_session_response(session) @router.get("/sessions/{session_id}/timer", response_model=TimerStatus) async def get_timer(session_id: str) -> TimerStatus: """Ruft den Timer-Status der aktuellen Phase ab.""" session = get_session_or_404(session_id) timer = PhaseTimer() status = timer.get_phase_status(session) return TimerStatus(**status) @router.get("/sessions/{session_id}/suggestions", response_model=SuggestionsResponse) async def get_suggestions( session_id: str, limit: int = Query(3, ge=1, le=10) ) -> SuggestionsResponse: """Ruft phasenspezifische Aktivitaets-Vorschlaege ab.""" session = get_session_or_404(session_id) engine = SuggestionEngine() response = engine.get_suggestions_response(session, limit) return SuggestionsResponse( suggestions=[SuggestionItem(**s) for s in response["suggestions"]], current_phase=response["current_phase"], phase_display_name=response["phase_display_name"], total_available=response["total_available"], ) # === Utility Endpoints === @router.get("/phases", response_model=PhasesListResponse) async def list_phases() -> PhasesListResponse: """Listet alle verfuegbaren Unterrichtsphasen mit Metadaten.""" phases = [] for phase_id, config in LESSON_PHASES.items(): phases.append({ "phase": phase_id, "display_name": config["display_name"], "default_duration_minutes": config["default_duration_minutes"], "activities": config["activities"], "icon": config["icon"], "description": config.get("description", ""), }) return PhasesListResponse(phases=phases) @router.get("/sessions", response_model=ActiveSessionsResponse) async def list_active_sessions( teacher_id: Optional[str] = Query(None) ) -> ActiveSessionsResponse: """Listet alle (optionally gefilterten) Sessions.""" sessions_list = [] for session in sessions.values(): if teacher_id and session.teacher_id != teacher_id: continue fsm = LessonStateMachine() sessions_list.append({ "session_id": session.session_id, "teacher_id": session.teacher_id, "class_id": session.class_id, "subject": session.subject, "current_phase": session.current_phase.value, "is_active": fsm.is_lesson_active(session), "lesson_started_at": session.lesson_started_at.isoformat() if session.lesson_started_at else None, }) return ActiveSessionsResponse(sessions=sessions_list, count=len(sessions_list)) @router.get("/health") async def health_check() -> Dict[str, Any]: """Health-Check fuer den Classroom Service.""" db_status = "disabled" if DB_ENABLED: try: db = SessionLocal() db.execute(text("SELECT 1")) db.close() db_status = "connected" except Exception as e: db_status = f"error: {str(e)}" return { "status": "healthy", "service": "classroom-engine", "active_sessions": len(sessions), "db_enabled": DB_ENABLED, "db_status": db_status, "timestamp": datetime.utcnow().isoformat(), }