"""
Classroom API - Teacher Context Endpoints (v1 API).

Endpoints fuer Teacher Context, Events, Routines und Antizipations-Engine.
"""

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

from fastapi import APIRouter, HTTPException, Query, Depends
from pydantic import BaseModel, Field
from sqlalchemy.orm import Session as DBSession

from .shared import init_db_if_needed, DB_ENABLED, logger

try:
    from classroom_engine.database import get_db, SessionLocal
    from classroom_engine.repository import (
        TeacherContextRepository, SchoolyearEventRepository, RecurringRoutineRepository
    )
    from classroom_engine.context_models import (
        MacroPhaseEnum, EventTypeEnum, EventStatusEnum,
        RoutineTypeEnum, RecurrencePatternEnum,
        FEDERAL_STATES, SCHOOL_TYPES
    )
    from classroom_engine.antizipation import SuggestionGenerator
except ImportError:
    FEDERAL_STATES = {}
    SCHOOL_TYPES = {}

router = APIRouter(prefix="/v1", tags=["Teacher Context"])


# === Pydantic Models ===

class SchoolInfo(BaseModel):
    federal_state: str
    federal_state_name: str
    school_type: str
    school_type_name: str


class SchoolYearInfo(BaseModel):
    id: str
    start: Optional[str]
    current_week: int


class MacroPhaseInfo(BaseModel):
    id: str
    label: str
    confidence: float


class CoreCounts(BaseModel):
    classes: int = 0
    exams_scheduled: int = 0
    corrections_pending: int = 0


class ContextFlags(BaseModel):
    onboarding_completed: bool = False
    has_classes: bool = False
    has_schedule: bool = False
    is_exam_period: bool = False
    is_before_holidays: bool = False


class TeacherContextResponse(BaseModel):
    schema_version: str = "1.0"
    teacher_id: str
    school: SchoolInfo
    school_year: SchoolYearInfo
    macro_phase: MacroPhaseInfo
    core_counts: CoreCounts
    flags: ContextFlags


class UpdateContextRequest(BaseModel):
    federal_state: Optional[str] = None
    school_type: Optional[str] = None
    schoolyear: Optional[str] = None
    schoolyear_start: Optional[str] = None
    macro_phase: Optional[str] = None
    current_week: Optional[int] = None


class CreateEventRequest(BaseModel):
    title: str = Field(..., max_length=300)
    event_type: str = "other"
    start_date: str
    end_date: Optional[str] = None
    class_id: Optional[str] = None
    subject: Optional[str] = None
    description: str = ""
    needs_preparation: bool = False
    reminder_days_before: int = 3


class EventResponse(BaseModel):
    id: str
    teacher_id: str
    event_type: str
    title: str
    description: str
    start_date: str
    end_date: Optional[str]
    class_id: Optional[str]
    subject: Optional[str]
    status: str
    needs_preparation: bool
    preparation_done: bool
    reminder_days_before: int


class CreateRoutineRequest(BaseModel):
    title: str
    routine_type: str = "other"
    recurrence_pattern: str = "weekly"
    day_of_week: Optional[int] = None
    day_of_month: Optional[int] = None
    time_of_day: Optional[str] = None
    duration_minutes: int = 60
    description: str = ""


class RoutineResponse(BaseModel):
    id: str
    teacher_id: str
    routine_type: str
    title: str
    description: str
    recurrence_pattern: str
    day_of_week: Optional[int]
    day_of_month: Optional[int]
    time_of_day: Optional[str]
    duration_minutes: int
    is_active: bool


# === Helper Functions ===

def get_macro_phase_label(phase) -> str:
    """Gibt den Anzeigenamen einer Makro-Phase zurueck."""
    labels = {
        "onboarding": "Einrichtung",
        "schuljahresstart": "Schuljahresstart",
        "unterrichtsaufbau": "Unterrichtsaufbau",
        "leistungsphase_1": "Leistungsphase 1",
        "halbjahresabschluss": "Halbjahresabschluss",
        "leistungsphase_2": "Leistungsphase 2",
        "jahresabschluss": "Jahresabschluss",
    }
    phase_value = phase.value if hasattr(phase, 'value') else str(phase)
    return labels.get(phase_value, phase_value)


def get_default_context_response(teacher_id: str) -> TeacherContextResponse:
    """Gibt eine Default-Context-Response zurueck."""
    return TeacherContextResponse(
        teacher_id=teacher_id,
        school=SchoolInfo(
            federal_state="BY",
            federal_state_name="Bayern",
            school_type="gymnasium",
            school_type_name="Gymnasium",
        ),
        school_year=SchoolYearInfo(id="2024-2025", start=None, current_week=1),
        macro_phase=MacroPhaseInfo(id="onboarding", label="Einrichtung", confidence=1.0),
        core_counts=CoreCounts(),
        flags=ContextFlags(),
    )


# === Context Endpoints ===

@router.get("/context", response_model=TeacherContextResponse)
async def get_teacher_context(teacher_id: str = Query(...)):
    """Liefert den aktuellen Makro-Kontext eines Lehrers."""
    if not DB_ENABLED:
        return get_default_context_response(teacher_id)

    try:
        db = SessionLocal()
        repo = TeacherContextRepository(db)
        context = repo.get_or_create(teacher_id)

        event_repo = SchoolyearEventRepository(db)
        upcoming_exams = event_repo.get_upcoming(teacher_id, days=30)
        exams_count = len([e for e in upcoming_exams if e.event_type.value == "exam"])

        result = TeacherContextResponse(
            teacher_id=teacher_id,
            school=SchoolInfo(
                federal_state=context.federal_state or "BY",
                federal_state_name=FEDERAL_STATES.get(context.federal_state, ""),
                school_type=context.school_type or "gymnasium",
                school_type_name=SCHOOL_TYPES.get(context.school_type, ""),
            ),
            school_year=SchoolYearInfo(
                id=context.schoolyear or "2024-2025",
                start=context.schoolyear_start.isoformat() if context.schoolyear_start else None,
                current_week=context.current_week or 1,
            ),
            macro_phase=MacroPhaseInfo(
                id=context.macro_phase.value,
                label=get_macro_phase_label(context.macro_phase),
                confidence=1.0,
            ),
            core_counts=CoreCounts(
                classes=1 if context.has_classes else 0,
                exams_scheduled=exams_count,
            ),
            flags=ContextFlags(
                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,
            ),
        )
        db.close()
        return result
    except Exception as e:
        logger.error(f"Failed to get teacher context: {e}")
        raise HTTPException(status_code=500, detail=f"Fehler beim Laden des Kontexts: {e}")


@router.put("/context", response_model=TeacherContextResponse)
async def update_teacher_context(teacher_id: str, request: UpdateContextRequest):
    """Aktualisiert den Kontext eines Lehrers."""
    if not DB_ENABLED:
        raise HTTPException(status_code=503, detail="Datenbank nicht verfuegbar")

    try:
        db = SessionLocal()
        repo = TeacherContextRepository(db)

        if request.federal_state and request.federal_state not in FEDERAL_STATES:
            raise HTTPException(status_code=400, detail=f"Ungueltiges Bundesland: {request.federal_state}")
        if request.school_type and request.school_type not in SCHOOL_TYPES:
            raise HTTPException(status_code=400, detail=f"Ungueltige Schulart: {request.school_type}")

        schoolyear_start = None
        if request.schoolyear_start:
            schoolyear_start = datetime.fromisoformat(request.schoolyear_start.replace('Z', '+00:00'))

        repo.update_context(
            teacher_id=teacher_id,
            federal_state=request.federal_state,
            school_type=request.school_type,
            schoolyear=request.schoolyear,
            schoolyear_start=schoolyear_start,
            macro_phase=request.macro_phase,
            current_week=request.current_week,
        )
        db.close()

        return await get_teacher_context(teacher_id)
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Failed to update teacher context: {e}")
        raise HTTPException(status_code=500, detail=f"Fehler beim Aktualisieren: {e}")


@router.post("/context/complete-onboarding")
async def complete_onboarding(teacher_id: str = Query(...)):
    """Markiert das Onboarding als abgeschlossen."""
    if not DB_ENABLED:
        return {"success": True, "macro_phase": "schuljahresstart", "note": "DB not available"}

    try:
        db = SessionLocal()
        repo = TeacherContextRepository(db)
        context = repo.complete_onboarding(teacher_id)
        db.close()
        return {"success": True, "macro_phase": context.macro_phase.value, "teacher_id": teacher_id}
    except Exception as e:
        logger.error(f"Failed to complete onboarding: {e}")
        raise HTTPException(status_code=500, detail=f"Fehler: {e}")


@router.post("/context/reset-onboarding")
async def reset_onboarding(teacher_id: str = Query(...)):
    """Setzt das Onboarding zurueck (fuer Tests)."""
    if not DB_ENABLED:
        return {"success": True, "macro_phase": "onboarding", "note": "DB not available"}

    try:
        db = SessionLocal()
        repo = TeacherContextRepository(db)
        context = repo.get_or_create(teacher_id)
        context.onboarding_completed = False
        context.macro_phase = MacroPhaseEnum.ONBOARDING
        db.commit()
        db.close()
        return {"success": True, "macro_phase": "onboarding", "teacher_id": teacher_id}
    except Exception as e:
        logger.error(f"Failed to reset onboarding: {e}")
        raise HTTPException(status_code=500, detail=f"Fehler: {e}")


# === Events Endpoints ===

@router.get("/events")
async def get_events(
    teacher_id: str = Query(...),
    status: Optional[str] = None,
    event_type: Optional[str] = None,
    limit: int = 50
):
    """Holt Events eines Lehrers."""
    if not DB_ENABLED:
        return {"events": [], "count": 0}

    try:
        db = SessionLocal()
        repo = SchoolyearEventRepository(db)
        events = repo.get_by_teacher(teacher_id, status=status, event_type=event_type, limit=limit)
        result = {"events": [repo.to_dict(e) for e in events], "count": len(events)}
        db.close()
        return result
    except Exception as e:
        logger.error(f"Failed to get events: {e}")
        raise HTTPException(status_code=500, detail=f"Fehler: {e}")


@router.get("/events/upcoming")
async def get_upcoming_events(teacher_id: str = Query(...), days: int = 30, limit: int = 10):
    """Holt anstehende Events der naechsten X Tage."""
    if not DB_ENABLED:
        return {"events": [], "count": 0}

    try:
        db = SessionLocal()
        repo = SchoolyearEventRepository(db)
        events = repo.get_upcoming(teacher_id, days=days, limit=limit)
        result = {"events": [repo.to_dict(e) for e in events], "count": len(events)}
        db.close()
        return result
    except Exception as e:
        logger.error(f"Failed to get upcoming events: {e}")
        raise HTTPException(status_code=500, detail=f"Fehler: {e}")


@router.post("/events", response_model=EventResponse)
async def create_event(teacher_id: str, request: CreateEventRequest):
    """Erstellt ein neues Schuljahr-Event."""
    if not DB_ENABLED:
        raise HTTPException(status_code=503, detail="Datenbank nicht verfuegbar")

    try:
        db = SessionLocal()
        repo = SchoolyearEventRepository(db)
        start_date = datetime.fromisoformat(request.start_date.replace('Z', '+00:00'))
        end_date = datetime.fromisoformat(request.end_date.replace('Z', '+00:00')) if request.end_date else None

        event = repo.create(
            teacher_id=teacher_id,
            title=request.title,
            event_type=request.event_type,
            start_date=start_date,
            end_date=end_date,
            class_id=request.class_id,
            subject=request.subject,
            description=request.description,
            needs_preparation=request.needs_preparation,
            reminder_days_before=request.reminder_days_before,
        )

        result = EventResponse(
            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(),
            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,
        )
        db.close()
        return result
    except Exception as e:
        logger.error(f"Failed to create event: {e}")
        raise HTTPException(status_code=500, detail=f"Fehler: {e}")


@router.delete("/events/{event_id}")
async def delete_event(event_id: str):
    """Loescht ein Event."""
    if not DB_ENABLED:
        raise HTTPException(status_code=503, detail="Datenbank nicht verfuegbar")

    try:
        db = SessionLocal()
        repo = SchoolyearEventRepository(db)
        if repo.delete(event_id):
            db.close()
            return {"success": True, "deleted_id": event_id}
        db.close()
        raise HTTPException(status_code=404, detail="Event nicht gefunden")
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Failed to delete event: {e}")
        raise HTTPException(status_code=500, detail=f"Fehler: {e}")


# === Routines Endpoints ===

@router.get("/routines")
async def get_routines(
    teacher_id: str = Query(...),
    is_active: bool = True,
    routine_type: Optional[str] = None
):
    """Holt Routinen eines Lehrers."""
    if not DB_ENABLED:
        return {"routines": [], "count": 0}

    try:
        db = SessionLocal()
        repo = RecurringRoutineRepository(db)
        routines = repo.get_by_teacher(teacher_id, is_active=is_active, routine_type=routine_type)
        result = {"routines": [repo.to_dict(r) for r in routines], "count": len(routines)}
        db.close()
        return result
    except Exception as e:
        logger.error(f"Failed to get routines: {e}")
        raise HTTPException(status_code=500, detail=f"Fehler: {e}")


@router.get("/routines/today")
async def get_today_routines(teacher_id: str = Query(...)):
    """Holt Routinen die heute stattfinden."""
    if not DB_ENABLED:
        return {"routines": [], "count": 0}

    try:
        db = SessionLocal()
        repo = RecurringRoutineRepository(db)
        routines = repo.get_today(teacher_id)
        result = {"routines": [repo.to_dict(r) for r in routines], "count": len(routines)}
        db.close()
        return result
    except Exception as e:
        logger.error(f"Failed to get today's routines: {e}")
        raise HTTPException(status_code=500, detail=f"Fehler: {e}")


@router.post("/routines", response_model=RoutineResponse)
async def create_routine(teacher_id: str, request: CreateRoutineRequest):
    """Erstellt eine neue wiederkehrende Routine."""
    if not DB_ENABLED:
        raise HTTPException(status_code=503, detail="Datenbank nicht verfuegbar")

    try:
        db = SessionLocal()
        repo = RecurringRoutineRepository(db)
        routine = repo.create(
            teacher_id=teacher_id,
            title=request.title,
            routine_type=request.routine_type,
            recurrence_pattern=request.recurrence_pattern,
            day_of_week=request.day_of_week,
            day_of_month=request.day_of_month,
            time_of_day=request.time_of_day,
            duration_minutes=request.duration_minutes,
            description=request.description,
        )

        result = RoutineResponse(
            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,
        )
        db.close()
        return result
    except Exception as e:
        logger.error(f"Failed to create routine: {e}")
        raise HTTPException(status_code=500, detail=f"Fehler: {e}")


@router.delete("/routines/{routine_id}")
async def delete_routine(routine_id: str):
    """Loescht eine Routine."""
    if not DB_ENABLED:
        raise HTTPException(status_code=503, detail="Datenbank nicht verfuegbar")

    try:
        db = SessionLocal()
        repo = RecurringRoutineRepository(db)
        if repo.delete(routine_id):
            db.close()
            return {"success": True, "deleted_id": routine_id}
        db.close()
        raise HTTPException(status_code=404, detail="Routine nicht gefunden")
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Failed to delete routine: {e}")
        raise HTTPException(status_code=500, detail=f"Fehler: {e}")


# === Static Data Endpoints ===

@router.get("/federal-states")
async def get_federal_states_list():
    """Gibt alle Bundeslaender zurueck."""
    return {"federal_states": [{"id": k, "name": v} for k, v in FEDERAL_STATES.items()]}


@router.get("/school-types")
async def get_school_types_list():
    """Gibt alle Schularten zurueck."""
    return {"school_types": [{"id": k, "name": v} for k, v in SCHOOL_TYPES.items()]}


@router.get("/macro-phases")
async def get_macro_phases_list():
    """Gibt alle Makro-Phasen zurueck."""
    return {
        "macro_phases": [
            {"id": "onboarding", "label": "Einrichtung", "order": 1},
            {"id": "schuljahresstart", "label": "Schuljahresstart", "order": 2},
            {"id": "unterrichtsaufbau", "label": "Unterrichtsaufbau", "order": 3},
            {"id": "leistungsphase_1", "label": "Leistungsphase 1", "order": 4},
            {"id": "halbjahresabschluss", "label": "Halbjahresabschluss", "order": 5},
            {"id": "leistungsphase_2", "label": "Leistungsphase 2", "order": 6},
            {"id": "jahresabschluss", "label": "Jahresabschluss", "order": 7},
        ]
    }


@router.get("/event-types")
async def get_event_types_list():
    """Gibt alle Event-Typen zurueck."""
    return {
        "event_types": [
            {"id": "exam", "label": "Klassenarbeit/Klausur"},
            {"id": "parent_evening", "label": "Elternabend"},
            {"id": "trip", "label": "Klassenfahrt/Ausflug"},
            {"id": "project", "label": "Projektwoche"},
            {"id": "other", "label": "Sonstiges"},
        ]
    }


@router.get("/routine-types")
async def get_routine_types_list():
    """Gibt alle Routine-Typen zurueck."""
    return {
        "routine_types": [
            {"id": "teacher_conference", "label": "Lehrerkonferenz"},
            {"id": "subject_conference", "label": "Fachkonferenz"},
            {"id": "office_hours", "label": "Sprechstunde"},
            {"id": "correction_time", "label": "Korrekturzeit"},
            {"id": "other", "label": "Sonstiges"},
        ]
    }


# === Antizipations-Engine ===

@router.get("/suggestions")
async def get_suggestions(teacher_id: str = Query(...), limit: int = Query(5, ge=1, le=20)):
    """Generiert kontextbasierte Vorschlaege fuer einen Lehrer."""
    if not DB_ENABLED:
        return {
            "active_contexts": [],
            "suggestions": [],
            "signals_summary": {"macro_phase": "onboarding"},
            "total_suggestions": 0,
        }

    try:
        db = SessionLocal()
        generator = SuggestionGenerator(db)
        result = generator.generate(teacher_id, limit=limit)
        db.close()
        return result
    except Exception as e:
        logger.error(f"Failed to generate suggestions: {e}")
        raise HTTPException(status_code=500, detail=f"Fehler: {e}")


# === Sidebar ===

@router.get("/sidebar")
async def get_sidebar(teacher_id: str = Query(...), mode: str = Query("companion")):
    """Generiert das dynamische Sidebar-Model."""
    if mode == "companion":
        return {
            "mode": "companion",
            "sections": [
                {"id": "SEARCH", "type": "search_bar", "placeholder": "Suchen..."},
                {"id": "NOW_RELEVANT", "type": "list", "title": "Jetzt relevant", "items": []},
                {
                    "id": "ALL_MODULES",
                    "type": "folder",
                    "label": "Alle Module",
                    "collapsed": True,
                    "items": [
                        {"id": "lesson", "label": "Stundenmodus", "icon": "timer"},
                        {"id": "classes", "label": "Klassen", "icon": "groups"},
                        {"id": "exams", "label": "Klausuren", "icon": "quiz"},
                    ],
                },
            ],
        }
    return {
        "mode": "classic",
        "sections": [
            {
                "id": "NAVIGATION",
                "type": "tree",
                "items": [
                    {"id": "dashboard", "label": "Dashboard", "icon": "dashboard"},
                    {"id": "lesson", "label": "Stundenmodus", "icon": "timer"},
                    {"id": "classes", "label": "Klassen", "icon": "groups"},
                ],
            }
        ],
    }


# === Schuljahres-Pfad ===

@router.get("/path")
async def get_schoolyear_path(teacher_id: str = Query(...)):
    """Generiert den Schuljahres-Pfad mit Meilensteinen."""
    current_phase = "onboarding"
    if DB_ENABLED:
        try:
            db = SessionLocal()
            repo = TeacherContextRepository(db)
            context = repo.get_or_create(teacher_id)
            current_phase = context.macro_phase.value
            db.close()
        except Exception as e:
            logger.warning(f"Failed to get context for path: {e}")

    phase_order = [
        "onboarding", "schuljahresstart", "unterrichtsaufbau",
        "leistungsphase_1", "halbjahresabschluss", "leistungsphase_2", "jahresabschluss",
    ]
    current_index = phase_order.index(current_phase) if current_phase in phase_order else 0

    milestones = [
        {"id": "MS_START", "label": "Start", "phase": "onboarding"},
        {"id": "MS_SETUP", "label": "Einrichtung", "phase": "schuljahresstart"},
        {"id": "MS_ROUTINE", "label": "Routinen", "phase": "unterrichtsaufbau"},
        {"id": "MS_EXAM_1", "label": "Klausuren", "phase": "leistungsphase_1"},
        {"id": "MS_HALFYEAR", "label": "Halbjahr", "phase": "halbjahresabschluss"},
        {"id": "MS_EXAM_2", "label": "Pruefungen", "phase": "leistungsphase_2"},
        {"id": "MS_END", "label": "Abschluss", "phase": "jahresabschluss"},
    ]

    for i, milestone in enumerate(milestones):
        phase_index = phase_order.index(milestone["phase"])
        if phase_index < current_index:
            milestone["status"] = "done"
        elif phase_index == current_index:
            milestone["status"] = "current"
        else:
            milestone["status"] = "upcoming"

    return {
        "milestones": milestones,
        "current_milestone_id": milestones[current_index]["id"],
        "progress_percent": int((current_index / (len(phase_order) - 1)) * 100),
    }
