"""
Session & Teacher Settings Repositories.

CRUD-Operationen fuer LessonSessions und Lehrer-Einstellungen.
"""
from typing import Optional, List, Dict

from sqlalchemy.orm import Session as DBSession

from .db_models import (
    LessonSessionDB, LessonPhaseEnum, TeacherSettingsDB,
)
from .models import (
    LessonSession, LessonPhase, get_default_durations,
)


class SessionRepository:
    """Repository fuer LessonSession CRUD-Operationen."""

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

    # ==================== CREATE ====================

    def create(self, session: LessonSession) -> LessonSessionDB:
        """
        Erstellt eine neue Session in der Datenbank.

        Args:
            session: LessonSession Dataclass

        Returns:
            LessonSessionDB Model
        """
        db_session = LessonSessionDB(
            id=session.session_id,
            teacher_id=session.teacher_id,
            class_id=session.class_id,
            subject=session.subject,
            topic=session.topic,
            current_phase=LessonPhaseEnum(session.current_phase.value),
            is_paused=session.is_paused,
            lesson_started_at=session.lesson_started_at,
            lesson_ended_at=session.lesson_ended_at,
            phase_started_at=session.phase_started_at,
            pause_started_at=session.pause_started_at,
            total_paused_seconds=session.total_paused_seconds,
            phase_durations=session.phase_durations,
            phase_history=session.phase_history,
            notes=session.notes,
            homework=session.homework,
        )
        self.db.add(db_session)
        self.db.commit()
        self.db.refresh(db_session)
        return db_session

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

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

    def get_active_by_teacher(self, teacher_id: str) -> List[LessonSessionDB]:
        """Holt alle aktiven Sessions eines Lehrers."""
        return self.db.query(LessonSessionDB).filter(
            LessonSessionDB.teacher_id == teacher_id,
            LessonSessionDB.current_phase != LessonPhaseEnum.ENDED
        ).all()

    def get_history_by_teacher(
        self,
        teacher_id: str,
        limit: int = 20,
        offset: int = 0
    ) -> List[LessonSessionDB]:
        """Holt Session-History eines Lehrers (Feature f17)."""
        return self.db.query(LessonSessionDB).filter(
            LessonSessionDB.teacher_id == teacher_id,
            LessonSessionDB.current_phase == LessonPhaseEnum.ENDED
        ).order_by(
            LessonSessionDB.lesson_ended_at.desc()
        ).offset(offset).limit(limit).all()

    def get_by_class(
        self,
        class_id: str,
        limit: int = 20
    ) -> List[LessonSessionDB]:
        """Holt Sessions einer Klasse."""
        return self.db.query(LessonSessionDB).filter(
            LessonSessionDB.class_id == class_id
        ).order_by(
            LessonSessionDB.created_at.desc()
        ).limit(limit).all()

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

    def update(self, session: LessonSession) -> Optional[LessonSessionDB]:
        """
        Aktualisiert eine bestehende Session.

        Args:
            session: LessonSession Dataclass mit aktualisierten Werten

        Returns:
            Aktualisierte LessonSessionDB oder None
        """
        db_session = self.get_by_id(session.session_id)
        if not db_session:
            return None

        db_session.current_phase = LessonPhaseEnum(session.current_phase.value)
        db_session.is_paused = session.is_paused
        db_session.lesson_started_at = session.lesson_started_at
        db_session.lesson_ended_at = session.lesson_ended_at
        db_session.phase_started_at = session.phase_started_at
        db_session.pause_started_at = session.pause_started_at
        db_session.total_paused_seconds = session.total_paused_seconds
        db_session.phase_durations = session.phase_durations
        db_session.phase_history = session.phase_history
        db_session.notes = session.notes
        db_session.homework = session.homework

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

    def update_notes(
        self,
        session_id: str,
        notes: str,
        homework: str
    ) -> Optional[LessonSessionDB]:
        """Aktualisiert nur Notizen und Hausaufgaben."""
        db_session = self.get_by_id(session_id)
        if not db_session:
            return None

        db_session.notes = notes
        db_session.homework = homework

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

    # ==================== DELETE ====================

    def delete(self, session_id: str) -> bool:
        """Loescht eine Session."""
        db_session = self.get_by_id(session_id)
        if not db_session:
            return False

        self.db.delete(db_session)
        self.db.commit()
        return True

    # ==================== CONVERSION ====================

    def to_dataclass(self, db_session: LessonSessionDB) -> LessonSession:
        """
        Konvertiert DB-Model zu Dataclass.

        Args:
            db_session: LessonSessionDB Model

        Returns:
            LessonSession Dataclass
        """
        return LessonSession(
            session_id=db_session.id,
            teacher_id=db_session.teacher_id,
            class_id=db_session.class_id,
            subject=db_session.subject,
            topic=db_session.topic,
            current_phase=LessonPhase(db_session.current_phase.value),
            phase_started_at=db_session.phase_started_at,
            lesson_started_at=db_session.lesson_started_at,
            lesson_ended_at=db_session.lesson_ended_at,
            is_paused=db_session.is_paused,
            pause_started_at=db_session.pause_started_at,
            total_paused_seconds=db_session.total_paused_seconds or 0,
            phase_durations=db_session.phase_durations or get_default_durations(),
            phase_history=db_session.phase_history or [],
            notes=db_session.notes or "",
            homework=db_session.homework or "",
        )


class TeacherSettingsRepository:
    """Repository fuer Lehrer-Einstellungen (Feature f16)."""

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

    def get_or_create(self, teacher_id: str) -> TeacherSettingsDB:
        """Holt oder erstellt Einstellungen fuer einen Lehrer."""
        settings = self.db.query(TeacherSettingsDB).filter(
            TeacherSettingsDB.teacher_id == teacher_id
        ).first()

        if not settings:
            settings = TeacherSettingsDB(
                teacher_id=teacher_id,
                default_phase_durations=get_default_durations(),
            )
            self.db.add(settings)
            self.db.commit()
            self.db.refresh(settings)

        return settings

    def update_phase_durations(
        self,
        teacher_id: str,
        durations: Dict[str, int]
    ) -> TeacherSettingsDB:
        """Aktualisiert die Standard-Phasendauern."""
        settings = self.get_or_create(teacher_id)
        settings.default_phase_durations = durations
        self.db.commit()
        self.db.refresh(settings)
        return settings

    def update_preferences(
        self,
        teacher_id: str,
        audio_enabled: Optional[bool] = None,
        high_contrast: Optional[bool] = None,
        show_statistics: Optional[bool] = None
    ) -> TeacherSettingsDB:
        """Aktualisiert UI-Praeferenzen."""
        settings = self.get_or_create(teacher_id)

        if audio_enabled is not None:
            settings.audio_enabled = audio_enabled
        if high_contrast is not None:
            settings.high_contrast = high_contrast
        if show_statistics is not None:
            settings.show_statistics = show_statistics

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