"""
Classroom API - Materials Routes

Phase materials management endpoints (Feature f19).
"""

from uuid import uuid4
from typing import Dict, Optional
from datetime import datetime
import logging

from fastapi import APIRouter, HTTPException, Query

from classroom_engine import (
    PhaseMaterial,
    MaterialType,
)

from ..models import (
    CreateMaterialRequest,
    UpdateMaterialRequest,
    MaterialResponse,
    MaterialListResponse,
)
from ..services.persistence import (
    init_db_if_needed,
    DB_ENABLED,
    SessionLocal,
)

logger = logging.getLogger(__name__)

router = APIRouter(tags=["Materials"])

# In-Memory Storage fuer Materialien (Fallback)
_materials: Dict[str, PhaseMaterial] = {}


def _build_material_response(mat: PhaseMaterial) -> MaterialResponse:
    """Baut eine MaterialResponse aus einem PhaseMaterial-Objekt."""
    return MaterialResponse(
        material_id=mat.material_id,
        teacher_id=mat.teacher_id,
        title=mat.title,
        material_type=mat.material_type.value,
        url=mat.url,
        description=mat.description,
        phase=mat.phase,
        subject=mat.subject,
        grade_level=mat.grade_level,
        tags=mat.tags,
        is_public=mat.is_public,
        usage_count=mat.usage_count,
        session_id=mat.session_id,
        created_at=mat.created_at.isoformat() if mat.created_at else None,
        updated_at=mat.updated_at.isoformat() if mat.updated_at else None,
    )


@router.post("/materials", response_model=MaterialResponse, status_code=201)
async def create_material(request: CreateMaterialRequest) -> MaterialResponse:
    """
    Erstellt ein neues Material (Feature f19).
    """
    init_db_if_needed()

    try:
        mat_type = MaterialType(request.material_type)
    except ValueError:
        mat_type = MaterialType.DOCUMENT

    material = PhaseMaterial(
        material_id=str(uuid4()),
        teacher_id=request.teacher_id,
        title=request.title,
        material_type=mat_type,
        url=request.url,
        description=request.description,
        phase=request.phase,
        subject=request.subject,
        grade_level=request.grade_level,
        tags=request.tags,
        is_public=request.is_public,
        usage_count=0,
        session_id=request.session_id,
        created_at=datetime.utcnow(),
    )

    # Persistieren wenn DB verfuegbar
    if DB_ENABLED:
        try:
            from classroom_engine.repository import MaterialRepository
            db = SessionLocal()
            repo = MaterialRepository(db)
            repo.create(material)
            db.close()
        except Exception as e:
            logger.warning(f"DB persist failed for material: {e}")

    _materials[material.material_id] = material
    return _build_material_response(material)


@router.get("/materials", response_model=MaterialListResponse)
async def list_materials(
    teacher_id: str = Query(..., description="ID des Lehrers"),
    phase: Optional[str] = Query(None, description="Filter nach Phase"),
    subject: Optional[str] = Query(None, description="Filter nach Fach"),
    include_public: bool = Query(True, description="Oeffentliche Materialien einbeziehen"),
    limit: int = Query(50, ge=1, le=100)
) -> MaterialListResponse:
    """
    Listet Materialien eines Lehrers (Feature f19).
    """
    init_db_if_needed()

    materials_list = []

    # Aus DB laden wenn verfuegbar
    if DB_ENABLED:
        try:
            from classroom_engine.repository import MaterialRepository
            db = SessionLocal()
            repo = MaterialRepository(db)
            if phase:
                db_materials = repo.get_by_phase(phase, teacher_id, include_public)
            else:
                db_materials = repo.get_by_teacher(teacher_id, phase, subject, limit)

            for db_mat in db_materials:
                mat = repo.to_dataclass(db_mat)
                _materials[mat.material_id] = mat
                materials_list.append(_build_material_response(mat))
            db.close()
            return MaterialListResponse(materials=materials_list, total=len(materials_list))
        except Exception as e:
            logger.warning(f"DB read failed for materials: {e}")

    # Fallback auf Memory
    for mat in _materials.values():
        if mat.teacher_id != teacher_id and not (include_public and mat.is_public):
            continue
        if phase and mat.phase != phase:
            continue
        if subject and mat.subject != subject:
            continue
        materials_list.append(_build_material_response(mat))

    return MaterialListResponse(materials=materials_list[:limit], total=len(materials_list))


@router.get("/materials/by-phase/{phase}", response_model=MaterialListResponse)
async def get_materials_by_phase(
    phase: str,
    teacher_id: str = Query(..., description="ID des Lehrers"),
    subject: Optional[str] = Query(None, description="Filter nach Fach"),
    limit: int = Query(50, ge=1, le=100)
) -> MaterialListResponse:
    """
    Holt Materialien fuer eine bestimmte Phase (Feature f19).
    """
    return await list_materials(teacher_id=teacher_id, phase=phase, subject=subject, limit=limit)


@router.get("/materials/{material_id}", response_model=MaterialResponse)
async def get_material(material_id: str) -> MaterialResponse:
    """
    Ruft ein einzelnes Material ab (Feature f19).
    """
    init_db_if_needed()

    # Aus Memory
    if material_id in _materials:
        return _build_material_response(_materials[material_id])

    # Aus DB laden
    if DB_ENABLED:
        try:
            from classroom_engine.repository import MaterialRepository
            db = SessionLocal()
            repo = MaterialRepository(db)
            db_mat = repo.get_by_id(material_id)
            db.close()
            if db_mat:
                mat = repo.to_dataclass(db_mat)
                _materials[mat.material_id] = mat
                return _build_material_response(mat)
        except Exception as e:
            logger.warning(f"DB read failed: {e}")

    raise HTTPException(status_code=404, detail="Material nicht gefunden")


@router.put("/materials/{material_id}", response_model=MaterialResponse)
async def update_material(
    material_id: str,
    request: UpdateMaterialRequest
) -> MaterialResponse:
    """
    Aktualisiert ein Material (Feature f19).
    """
    init_db_if_needed()

    # Aus Memory holen
    material = _materials.get(material_id)

    # Aus DB laden wenn nicht in Memory
    if not material and DB_ENABLED:
        try:
            from classroom_engine.repository import MaterialRepository
            db = SessionLocal()
            repo = MaterialRepository(db)
            db_mat = repo.get_by_id(material_id)
            db.close()
            if db_mat:
                material = repo.to_dataclass(db_mat)
                _materials[material.material_id] = material
        except Exception as e:
            logger.warning(f"DB read failed: {e}")

    if not material:
        raise HTTPException(status_code=404, detail="Material nicht gefunden")

    # Aktualisieren
    if request.title is not None:
        material.title = request.title
    if request.material_type is not None:
        try:
            material.material_type = MaterialType(request.material_type)
        except ValueError:
            raise HTTPException(status_code=400, detail="Ungueltiger Material-Typ")
    if request.url is not None:
        material.url = request.url
    if request.description is not None:
        material.description = request.description
    if request.phase is not None:
        material.phase = request.phase
    if request.subject is not None:
        material.subject = request.subject
    if request.grade_level is not None:
        material.grade_level = request.grade_level
    if request.tags is not None:
        material.tags = request.tags
    if request.is_public is not None:
        material.is_public = request.is_public

    material.updated_at = datetime.utcnow()

    # In DB aktualisieren
    if DB_ENABLED:
        try:
            from classroom_engine.repository import MaterialRepository
            db = SessionLocal()
            repo = MaterialRepository(db)
            repo.update(material)
            db.close()
        except Exception as e:
            logger.warning(f"DB update failed: {e}")

    _materials[material_id] = material
    return _build_material_response(material)


@router.post("/materials/{material_id}/attach/{session_id}")
async def attach_material_to_session(
    material_id: str,
    session_id: str
) -> MaterialResponse:
    """
    Verknuepft ein Material mit einer Session (Feature f19).
    """
    init_db_if_needed()

    material = _materials.get(material_id)

    if not material and DB_ENABLED:
        try:
            from classroom_engine.repository import MaterialRepository
            db = SessionLocal()
            repo = MaterialRepository(db)
            db_mat = repo.get_by_id(material_id)
            if db_mat:
                material = repo.to_dataclass(db_mat)
            db.close()
        except Exception as e:
            logger.warning(f"DB read failed: {e}")

    if not material:
        raise HTTPException(status_code=404, detail="Material nicht gefunden")

    material.session_id = session_id
    material.usage_count += 1
    material.updated_at = datetime.utcnow()

    if DB_ENABLED:
        try:
            from classroom_engine.repository import MaterialRepository
            db = SessionLocal()
            repo = MaterialRepository(db)
            repo.attach_to_session(material_id, session_id)
            db.close()
        except Exception as e:
            logger.warning(f"DB update failed: {e}")

    _materials[material_id] = material
    return _build_material_response(material)


@router.delete("/materials/{material_id}")
async def delete_material(material_id: str) -> Dict[str, str]:
    """
    Loescht ein Material (Feature f19).
    """
    init_db_if_needed()

    if material_id in _materials:
        del _materials[material_id]

    if DB_ENABLED:
        try:
            from classroom_engine.repository import MaterialRepository
            db = SessionLocal()
            repo = MaterialRepository(db)
            repo.delete(material_id)
            db.close()
        except Exception as e:
            logger.warning(f"DB delete failed: {e}")

    return {"status": "deleted", "material_id": material_id}
