"""
Teacher Context, Schoolyear Event & Recurring Routine Repositories.

CRUD-Operationen fuer Schuljahres-Kontext (Phase 8).
"""
from datetime import datetime
from typing import Optional, List, Dict, Any

from sqlalchemy.orm import Session as DBSession

from .context_models import (
    TeacherContextDB, SchoolyearEventDB, RecurringRoutineDB,
    MacroPhaseEnum, EventTypeEnum, EventStatusEnum,
    RoutineTypeEnum, RecurrencePatternEnum,
    FEDERAL_STATES, SCHOOL_TYPES,
)


class TeacherContextRepository:
    """Repository fuer Lehrer-Kontext CRUD-Operationen (Phase 8)."""

    def __init__(self, db: DBSession):
        self.db = db

    # ==================== CREATE / GET-OR-CREATE ====================

    def get_or_create(self, teacher_id: str) -> TeacherContextDB:
        """
        Holt den Kontext eines Lehrers oder erstellt einen neuen.

        Args:
            teacher_id: ID des Lehrers

        Returns:
            TeacherContextDB Model
        """
        context = self.get_by_teacher_id(teacher_id)
        if context:
            return context

        # Neuen Kontext erstellen
        from uuid import uuid4
        context = TeacherContextDB(
            id=str(uuid4()),
            teacher_id=teacher_id,
            macro_phase=MacroPhaseEnum.ONBOARDING,
        )
        self.db.add(context)
        self.db.commit()
        self.db.refresh(context)
        return context

    # ==================== READ ====================

    def get_by_teacher_id(self, teacher_id: str) -> Optional[TeacherContextDB]:
        """Holt den Kontext eines Lehrers."""
        return self.db.query(TeacherContextDB).filter(
            TeacherContextDB.teacher_id == teacher_id
        ).first()

    # ==================== UPDATE ====================

    def update_context(
        self,
        teacher_id: str,
        federal_state: str = None,
        school_type: str = None,
        schoolyear: str = None,
        schoolyear_start: datetime = None,
        macro_phase: str = None,
        current_week: int = None,
    ) -> Optional[TeacherContextDB]:
        """Aktualisiert den Kontext eines Lehrers."""
        context = self.get_or_create(teacher_id)

        if federal_state is not None:
            context.federal_state = federal_state
        if school_type is not None:
            context.school_type = school_type
        if schoolyear is not None:
            context.schoolyear = schoolyear
        if schoolyear_start is not None:
            context.schoolyear_start = schoolyear_start
        if macro_phase is not None:
            context.macro_phase = MacroPhaseEnum(macro_phase)
        if current_week is not None:
            context.current_week = current_week

        self.db.commit()
        self.db.refresh(context)
        return context

    def complete_onboarding(self, teacher_id: str) -> TeacherContextDB:
        """Markiert Onboarding als abgeschlossen."""
        context = self.get_or_create(teacher_id)
        context.onboarding_completed = True
        context.macro_phase = MacroPhaseEnum.SCHULJAHRESSTART
        self.db.commit()
        self.db.refresh(context)
        return context

    def update_flags(
        self,
        teacher_id: str,
        has_classes: bool = None,
        has_schedule: bool = None,
        is_exam_period: bool = None,
        is_before_holidays: bool = None,
    ) -> TeacherContextDB:
        """Aktualisiert die Status-Flags eines Kontexts."""
        context = self.get_or_create(teacher_id)

        if has_classes is not None:
            context.has_classes = has_classes
        if has_schedule is not None:
            context.has_schedule = has_schedule
        if is_exam_period is not None:
            context.is_exam_period = is_exam_period
        if is_before_holidays is not None:
            context.is_before_holidays = is_before_holidays

        self.db.commit()
        self.db.refresh(context)
        return context

    def to_dict(self, context: TeacherContextDB) -> Dict[str, Any]:
        """Konvertiert DB-Model zu Dictionary."""
        return {
            "id": context.id,
            "teacher_id": context.teacher_id,
            "school": {
                "federal_state": context.federal_state,
                "federal_state_name": FEDERAL_STATES.get(context.federal_state, ""),
                "school_type": context.school_type,
                "school_type_name": SCHOOL_TYPES.get(context.school_type, ""),
            },
            "school_year": {
                "id": context.schoolyear,
                "start": context.schoolyear_start.isoformat() if context.schoolyear_start else None,
                "current_week": context.current_week,
            },
            "macro_phase": {
                "id": context.macro_phase.value,
                "label": self._get_phase_label(context.macro_phase),
            },
            "flags": {
                "onboarding_completed": context.onboarding_completed,
                "has_classes": context.has_classes,
                "has_schedule": context.has_schedule,
                "is_exam_period": context.is_exam_period,
                "is_before_holidays": context.is_before_holidays,
            },
            "created_at": context.created_at.isoformat() if context.created_at else None,
            "updated_at": context.updated_at.isoformat() if context.updated_at else None,
        }

    def _get_phase_label(self, phase: MacroPhaseEnum) -> str:
        """Gibt den Anzeigenamen einer Makro-Phase zurueck."""
        labels = {
            MacroPhaseEnum.ONBOARDING: "Einrichtung",
            MacroPhaseEnum.SCHULJAHRESSTART: "Schuljahresstart",
            MacroPhaseEnum.UNTERRICHTSAUFBAU: "Unterrichtsaufbau",
            MacroPhaseEnum.LEISTUNGSPHASE_1: "Leistungsphase 1",
            MacroPhaseEnum.HALBJAHRESABSCHLUSS: "Halbjahresabschluss",
            MacroPhaseEnum.LEISTUNGSPHASE_2: "Leistungsphase 2",
            MacroPhaseEnum.JAHRESABSCHLUSS: "Jahresabschluss",
        }
        return labels.get(phase, phase.value)


class SchoolyearEventRepository:
    """Repository fuer Schuljahr-Events (Phase 8)."""

    def __init__(self, db: DBSession):
        self.db = db

    def create(
        self,
        teacher_id: str,
        title: str,
        start_date: datetime,
        event_type: str = "other",
        end_date: datetime = None,
        class_id: str = None,
        subject: str = None,
        description: str = "",
        needs_preparation: bool = True,
        reminder_days_before: int = 7,
        extra_data: Dict[str, Any] = None,
    ) -> SchoolyearEventDB:
        """Erstellt ein neues Schuljahr-Event."""
        from uuid import uuid4
        event = SchoolyearEventDB(
            id=str(uuid4()),
            teacher_id=teacher_id,
            title=title,
            event_type=EventTypeEnum(event_type),
            start_date=start_date,
            end_date=end_date,
            class_id=class_id,
            subject=subject,
            description=description,
            needs_preparation=needs_preparation,
            reminder_days_before=reminder_days_before,
            extra_data=extra_data or {},
        )
        self.db.add(event)
        self.db.commit()
        self.db.refresh(event)
        return event

    def get_by_id(self, event_id: str) -> Optional[SchoolyearEventDB]:
        """Holt ein Event nach ID."""
        return self.db.query(SchoolyearEventDB).filter(
            SchoolyearEventDB.id == event_id
        ).first()

    def get_by_teacher(
        self,
        teacher_id: str,
        status: str = None,
        event_type: str = None,
        limit: int = 50,
    ) -> List[SchoolyearEventDB]:
        """Holt Events eines Lehrers."""
        query = self.db.query(SchoolyearEventDB).filter(
            SchoolyearEventDB.teacher_id == teacher_id
        )
        if status:
            query = query.filter(SchoolyearEventDB.status == EventStatusEnum(status))
        if event_type:
            query = query.filter(SchoolyearEventDB.event_type == EventTypeEnum(event_type))

        return query.order_by(SchoolyearEventDB.start_date).limit(limit).all()

    def get_upcoming(
        self,
        teacher_id: str,
        days: int = 30,
        limit: int = 10,
    ) -> List[SchoolyearEventDB]:
        """Holt anstehende Events der naechsten X Tage."""
        from datetime import timedelta
        now = datetime.utcnow()
        end = now + timedelta(days=days)

        return self.db.query(SchoolyearEventDB).filter(
            SchoolyearEventDB.teacher_id == teacher_id,
            SchoolyearEventDB.start_date >= now,
            SchoolyearEventDB.start_date <= end,
            SchoolyearEventDB.status != EventStatusEnum.CANCELLED,
        ).order_by(SchoolyearEventDB.start_date).limit(limit).all()

    def update_status(
        self,
        event_id: str,
        status: str,
        preparation_done: bool = None,
    ) -> Optional[SchoolyearEventDB]:
        """Aktualisiert den Status eines Events."""
        event = self.get_by_id(event_id)
        if not event:
            return None

        event.status = EventStatusEnum(status)
        if preparation_done is not None:
            event.preparation_done = preparation_done

        self.db.commit()
        self.db.refresh(event)
        return event

    def delete(self, event_id: str) -> bool:
        """Loescht ein Event."""
        event = self.get_by_id(event_id)
        if not event:
            return False
        self.db.delete(event)
        self.db.commit()
        return True

    def to_dict(self, event: SchoolyearEventDB) -> Dict[str, Any]:
        """Konvertiert DB-Model zu Dictionary."""
        return {
            "id": event.id,
            "teacher_id": event.teacher_id,
            "event_type": event.event_type.value,
            "title": event.title,
            "description": event.description,
            "start_date": event.start_date.isoformat() if event.start_date else None,
            "end_date": event.end_date.isoformat() if event.end_date else None,
            "class_id": event.class_id,
            "subject": event.subject,
            "status": event.status.value,
            "needs_preparation": event.needs_preparation,
            "preparation_done": event.preparation_done,
            "reminder_days_before": event.reminder_days_before,
            "extra_data": event.extra_data,
            "created_at": event.created_at.isoformat() if event.created_at else None,
        }


class RecurringRoutineRepository:
    """Repository fuer wiederkehrende Routinen (Phase 8)."""

    def __init__(self, db: DBSession):
        self.db = db

    def create(
        self,
        teacher_id: str,
        title: str,
        routine_type: str = "other",
        recurrence_pattern: str = "weekly",
        day_of_week: int = None,
        day_of_month: int = None,
        time_of_day: str = None,  # Format: "14:00"
        duration_minutes: int = 60,
        description: str = "",
        valid_from: datetime = None,
        valid_until: datetime = None,
    ) -> RecurringRoutineDB:
        """Erstellt eine neue wiederkehrende Routine."""
        from uuid import uuid4
        from datetime import time as dt_time

        time_obj = None
        if time_of_day:
            parts = time_of_day.split(":")
            time_obj = dt_time(int(parts[0]), int(parts[1]))

        routine = RecurringRoutineDB(
            id=str(uuid4()),
            teacher_id=teacher_id,
            title=title,
            routine_type=RoutineTypeEnum(routine_type),
            recurrence_pattern=RecurrencePatternEnum(recurrence_pattern),
            day_of_week=day_of_week,
            day_of_month=day_of_month,
            time_of_day=time_obj,
            duration_minutes=duration_minutes,
            description=description,
            valid_from=valid_from,
            valid_until=valid_until,
        )
        self.db.add(routine)
        self.db.commit()
        self.db.refresh(routine)
        return routine

    def get_by_id(self, routine_id: str) -> Optional[RecurringRoutineDB]:
        """Holt eine Routine nach ID."""
        return self.db.query(RecurringRoutineDB).filter(
            RecurringRoutineDB.id == routine_id
        ).first()

    def get_by_teacher(
        self,
        teacher_id: str,
        is_active: bool = True,
        routine_type: str = None,
    ) -> List[RecurringRoutineDB]:
        """Holt Routinen eines Lehrers."""
        query = self.db.query(RecurringRoutineDB).filter(
            RecurringRoutineDB.teacher_id == teacher_id
        )
        if is_active is not None:
            query = query.filter(RecurringRoutineDB.is_active == is_active)
        if routine_type:
            query = query.filter(RecurringRoutineDB.routine_type == RoutineTypeEnum(routine_type))

        return query.all()

    def get_today(self, teacher_id: str) -> List[RecurringRoutineDB]:
        """Holt Routinen die heute stattfinden."""
        today = datetime.utcnow()
        day_of_week = today.weekday()  # 0 = Montag
        day_of_month = today.day

        routines = self.get_by_teacher(teacher_id, is_active=True)
        today_routines = []

        for routine in routines:
            if routine.recurrence_pattern == RecurrencePatternEnum.DAILY:
                today_routines.append(routine)
            elif routine.recurrence_pattern == RecurrencePatternEnum.WEEKLY:
                if routine.day_of_week == day_of_week:
                    today_routines.append(routine)
            elif routine.recurrence_pattern == RecurrencePatternEnum.BIWEEKLY:
                # Vereinfacht: Pruefen ob Tag passt (echte Logik braucht Startdatum)
                if routine.day_of_week == day_of_week:
                    today_routines.append(routine)
            elif routine.recurrence_pattern == RecurrencePatternEnum.MONTHLY:
                if routine.day_of_month == day_of_month:
                    today_routines.append(routine)

        return today_routines

    def update(
        self,
        routine_id: str,
        title: str = None,
        is_active: bool = None,
        day_of_week: int = None,
        time_of_day: str = None,
    ) -> Optional[RecurringRoutineDB]:
        """Aktualisiert eine Routine."""
        routine = self.get_by_id(routine_id)
        if not routine:
            return None

        if title is not None:
            routine.title = title
        if is_active is not None:
            routine.is_active = is_active
        if day_of_week is not None:
            routine.day_of_week = day_of_week
        if time_of_day is not None:
            from datetime import time as dt_time
            parts = time_of_day.split(":")
            routine.time_of_day = dt_time(int(parts[0]), int(parts[1]))

        self.db.commit()
        self.db.refresh(routine)
        return routine

    def delete(self, routine_id: str) -> bool:
        """Loescht eine Routine."""
        routine = self.get_by_id(routine_id)
        if not routine:
            return False
        self.db.delete(routine)
        self.db.commit()
        return True

    def to_dict(self, routine: RecurringRoutineDB) -> Dict[str, Any]:
        """Konvertiert DB-Model zu Dictionary."""
        return {
            "id": routine.id,
            "teacher_id": routine.teacher_id,
            "routine_type": routine.routine_type.value,
            "title": routine.title,
            "description": routine.description,
            "recurrence_pattern": routine.recurrence_pattern.value,
            "day_of_week": routine.day_of_week,
            "day_of_month": routine.day_of_month,
            "time_of_day": routine.time_of_day.isoformat() if routine.time_of_day else None,
            "duration_minutes": routine.duration_minutes,
            "is_active": routine.is_active,
            "valid_from": routine.valid_from.isoformat() if routine.valid_from else None,
            "valid_until": routine.valid_until.isoformat() if routine.valid_until else None,
            "created_at": routine.created_at.isoformat() if routine.created_at else None,
        }
