"""
Finite State Machine fuer Unterrichtsphasen.

Definiert die erlaubten Phasen-Uebergaenge und fuehrt Transitionen durch.
"""

from datetime import datetime
from typing import Optional, List, Dict

from .models import LessonPhase, LessonSession, LESSON_PHASES


class LessonStateMachine:
    """
    Finite State Machine fuer die Unterrichtsphasen.

    Erlaubte Uebergaenge:
    NOT_STARTED -> EINSTIEG -> ERARBEITUNG -> SICHERUNG -> TRANSFER -> REFLEXION -> ENDED
    """

    # Definiert erlaubte Uebergaenge: von_phase -> [moeglich_zu_phasen]
    TRANSITIONS: Dict[LessonPhase, List[LessonPhase]] = {
        LessonPhase.NOT_STARTED: [LessonPhase.EINSTIEG],
        LessonPhase.EINSTIEG: [LessonPhase.ERARBEITUNG],
        LessonPhase.ERARBEITUNG: [LessonPhase.SICHERUNG],
        LessonPhase.SICHERUNG: [LessonPhase.TRANSFER],
        LessonPhase.TRANSFER: [LessonPhase.REFLEXION],
        LessonPhase.REFLEXION: [LessonPhase.ENDED],
        LessonPhase.ENDED: [],  # Terminal State
    }

    # Phasen-Reihenfolge fuer Timeline
    PHASE_ORDER: List[LessonPhase] = [
        LessonPhase.EINSTIEG,
        LessonPhase.ERARBEITUNG,
        LessonPhase.SICHERUNG,
        LessonPhase.TRANSFER,
        LessonPhase.REFLEXION,
    ]

    def can_transition(self, from_phase: LessonPhase, to_phase: LessonPhase) -> bool:
        """
        Prueft ob ein Uebergang von from_phase zu to_phase erlaubt ist.

        Args:
            from_phase: Ausgangsphase
            to_phase: Zielphase

        Returns:
            True wenn Uebergang erlaubt, False sonst
        """
        allowed_targets = self.TRANSITIONS.get(from_phase, [])
        return to_phase in allowed_targets

    def next_phase(self, current: LessonPhase) -> Optional[LessonPhase]:
        """
        Gibt die naechste Phase zurueck (oder None wenn keine vorhanden).

        Args:
            current: Aktuelle Phase

        Returns:
            Naechste Phase oder None
        """
        transitions = self.TRANSITIONS.get(current, [])
        return transitions[0] if transitions else None

    def previous_phase(self, current: LessonPhase) -> Optional[LessonPhase]:
        """
        Gibt die vorherige Phase zurueck (oder None wenn keine vorhanden).

        Args:
            current: Aktuelle Phase

        Returns:
            Vorherige Phase oder None
        """
        if current == LessonPhase.NOT_STARTED or current == LessonPhase.ENDED:
            return None

        try:
            idx = self.PHASE_ORDER.index(current)
            if idx > 0:
                return self.PHASE_ORDER[idx - 1]
        except ValueError:
            pass

        return None

    def transition(self, session: LessonSession, to_phase: LessonPhase) -> LessonSession:
        """
        Fuehrt einen Phasen-Uebergang durch.

        Args:
            session: Die aktuelle Session
            to_phase: Zielphase

        Returns:
            Aktualisierte Session

        Raises:
            ValueError: Wenn Uebergang nicht erlaubt
        """
        if not self.can_transition(session.current_phase, to_phase):
            raise ValueError(
                f"Ungueltiger Uebergang: {session.current_phase.value} -> {to_phase.value}. "
                f"Erlaubte Ziele: {[p.value for p in self.TRANSITIONS.get(session.current_phase, [])]}"
            )

        now = datetime.utcnow()

        # Historie der aktuellen Phase speichern (wenn nicht NOT_STARTED)
        if session.phase_started_at and session.current_phase != LessonPhase.NOT_STARTED:
            duration_seconds = (now - session.phase_started_at).total_seconds()
            session.phase_history.append({
                "phase": session.current_phase.value,
                "started_at": session.phase_started_at.isoformat(),
                "ended_at": now.isoformat(),
                "duration_seconds": int(duration_seconds),
            })

        # State aktualisieren
        session.current_phase = to_phase
        session.phase_started_at = now

        # Spezielle Behandlung fuer Start und Ende
        if to_phase == LessonPhase.EINSTIEG:
            session.lesson_started_at = now
        elif to_phase == LessonPhase.ENDED:
            session.lesson_ended_at = now
            session.phase_started_at = None  # Beendete Stunde hat keinen aktiven Timer

        return session

    def get_phase_index(self, phase: LessonPhase) -> int:
        """
        Gibt den Index der Phase in der Reihenfolge zurueck.

        Args:
            phase: Die Phase

        Returns:
            Index (0-4) oder -1 fuer NOT_STARTED/ENDED
        """
        if phase in [LessonPhase.NOT_STARTED, LessonPhase.ENDED]:
            return -1

        try:
            return self.PHASE_ORDER.index(phase)
        except ValueError:
            return -1

    def get_phases_info(self, session: LessonSession) -> List[Dict]:
        """
        Gibt Informationen ueber alle Phasen fuer die Timeline zurueck.

        Args:
            session: Die aktuelle Session

        Returns:
            Liste mit Phasen-Informationen
        """
        current_index = self.get_phase_index(session.current_phase)

        phases_info = []
        for i, phase in enumerate(self.PHASE_ORDER):
            phase_id = phase.value
            phase_config = LESSON_PHASES.get(phase_id, {})

            phases_info.append({
                "phase": phase_id,
                "display_name": phase_config.get("display_name", phase_id.capitalize()),
                "icon": phase_config.get("icon", "circle"),
                "duration_minutes": session.phase_durations.get(
                    phase_id, phase_config.get("default_duration_minutes", 10)
                ),
                "is_completed": i < current_index if current_index >= 0 else session.current_phase == LessonPhase.ENDED,
                "is_current": i == current_index,
                "is_future": i > current_index if current_index >= 0 else session.current_phase == LessonPhase.NOT_STARTED,
            })

        return phases_info

    def is_lesson_active(self, session: LessonSession) -> bool:
        """
        Prueft ob die Stunde gerade aktiv ist.

        Args:
            session: Die Session

        Returns:
            True wenn aktiv, False sonst
        """
        return session.current_phase not in [LessonPhase.NOT_STARTED, LessonPhase.ENDED]

    def is_lesson_ended(self, session: LessonSession) -> bool:
        """
        Prueft ob die Stunde beendet ist.

        Args:
            session: Die Session

        Returns:
            True wenn beendet, False sonst
        """
        return session.current_phase == LessonPhase.ENDED

    def get_total_elapsed_seconds(self, session: LessonSession) -> int:
        """
        Berechnet die gesamte verstrichene Zeit seit Stundenbeginn.

        Args:
            session: Die Session

        Returns:
            Verstrichene Sekunden oder 0 wenn nicht gestartet
        """
        if not session.lesson_started_at:
            return 0

        end_time = session.lesson_ended_at or datetime.utcnow()
        return int((end_time - session.lesson_started_at).total_seconds())
