""" Antizipation Engine - Signal collector. Sammelt Signale aus verschiedenen Quellen: - TeacherContext (Makro-Phase, Schuljahr) - SchoolyearEvents (Klausuren, Elternabende, etc.) - RecurringRoutines (Konferenzen heute) - Zeit/Kalender (Wochenende, Ferien) """ import logging from datetime import datetime, timedelta from .antizipation_models import Signals logger = logging.getLogger(__name__) class SignalCollector: """ Sammelt Signale aus verschiedenen Quellen. """ def __init__(self, db_session=None): self.db = db_session def collect(self, teacher_id: str) -> Signals: """Sammelt alle Signale fuer einen Lehrer.""" signals = Signals() # Zeit-Signale self._collect_time_signals(signals) if self.db: # Kontext-Signale self._collect_context_signals(signals, teacher_id) # Event-Signale self._collect_event_signals(signals, teacher_id) # Routine-Signale self._collect_routine_signals(signals, teacher_id) return signals def _collect_time_signals(self, signals: Signals): """Sammelt zeitbasierte Signale.""" now = datetime.utcnow() signals.is_weekend = now.weekday() >= 5 # TODO: Ferien-Kalender pro Bundesland integrieren # Fuer jetzt: Dummy-Werte signals.is_before_holidays = False signals.days_until_holidays = 999 def _collect_context_signals(self, signals: Signals, teacher_id: str): """Sammelt Signale aus dem Teacher-Kontext.""" from .repository import TeacherContextRepository try: repo = TeacherContextRepository(self.db) context = repo.get_or_create(teacher_id) signals.macro_phase = context.macro_phase.value signals.current_week = context.current_week or 1 signals.onboarding_completed = context.onboarding_completed signals.has_classes = context.has_classes signals.has_schedule = context.has_schedule signals.classes_count = 1 if context.has_classes else 0 # Wochen seit Schuljahresstart berechnen if context.schoolyear_start: delta = datetime.utcnow() - context.schoolyear_start signals.weeks_since_start = max(0, delta.days // 7) signals.is_before_holidays = context.is_before_holidays except Exception as e: logger.warning(f"Failed to collect context signals: {e}") def _collect_event_signals(self, signals: Signals, teacher_id: str): """Sammelt Signale aus Events.""" from .repository import SchoolyearEventRepository try: repo = SchoolyearEventRepository(self.db) now = datetime.utcnow() # Alle anstehenden Events (30 Tage) upcoming = repo.get_upcoming(teacher_id, days=30, limit=20) signals.upcoming_events = [repo.to_dict(e) for e in upcoming] # Klausuren in den naechsten 7 Tagen seven_days = now + timedelta(days=7) signals.exams_in_7_days = [ repo.to_dict(e) for e in upcoming if e.event_type.value == "exam" and e.start_date <= seven_days ] signals.exams_scheduled_count = len([ e for e in upcoming if e.event_type.value == "exam" ]) # Klassenfahrten in 30 Tagen signals.trips_in_30_days = [ repo.to_dict(e) for e in upcoming if e.event_type.value == "trip" ] # Elternabende bald signals.parent_evenings_soon = [ repo.to_dict(e) for e in upcoming if e.event_type.value in ("parent_evening", "parent_consultation") ] except Exception as e: logger.warning(f"Failed to collect event signals: {e}") def _collect_routine_signals(self, signals: Signals, teacher_id: str): """Sammelt Signale aus Routinen.""" from .repository import RecurringRoutineRepository try: repo = RecurringRoutineRepository(self.db) today_routines = repo.get_today(teacher_id) signals.routines_today = [repo.to_dict(r) for r in today_routines] signals.has_conference_today = any( r.routine_type.value in ("teacher_conference", "subject_conference") for r in today_routines ) except Exception as e: logger.warning(f"Failed to collect routine signals: {e}")