"""Course management — CRUD, modules, lessons, enrollment, progress, AI content, BBB."""
import hashlib
import logging
import os
import uuid
from datetime import datetime
from urllib.parse import urlencode

from fastapi import APIRouter, Depends, HTTPException, Query, UploadFile, File
from pydantic import BaseModel, Field
from sqlalchemy import func
from sqlalchemy.orm import Session

from app.config import settings
from app.database import get_db
from app.models.course import (
    Course, CourseModule, CourseLesson, CourseEnrollment, CourseLessonProgress,
)
from app.models.question import Question
from app.models.quiz import Quiz
from app.models.user import User
from app.utils.auth import get_current_user

logger = logging.getLogger(__name__)
router = APIRouter()


# ── Schemas ──────────────────────────────────────────────────────────

class CourseCreate(BaseModel):
    title: str = Field(..., min_length=1, max_length=300)
    description: str | None = Field(None, max_length=5000)


class CourseUpdate(BaseModel):
    title: str | None = Field(None, max_length=300)
    description: str | None = Field(None, max_length=5000)
    requires_subscription: int | None = None


class ModuleCreate(BaseModel):
    title: str = Field(..., min_length=1, max_length=300)
    description: str | None = Field(None, max_length=2000)
    position: int | None = None


class ModuleUpdate(BaseModel):
    title: str | None = Field(None, max_length=300)
    description: str | None = Field(None, max_length=2000)
    position: int | None = None


class ModuleReorder(BaseModel):
    module_ids: list[int]


class LessonCreate(BaseModel):
    title: str = Field(..., min_length=1, max_length=300)
    lesson_type: str = "video"  # video, document, quiz, live
    content_text: str | None = None
    video_url: str | None = None
    quiz_id: int | None = None
    live_session_url: str | None = None
    live_session_start: str | None = None
    live_session_end: str | None = None
    duration_minutes: int | None = None
    is_required: int = 1
    position: int | None = None


class LessonUpdate(BaseModel):
    title: str | None = Field(None, max_length=300)
    lesson_type: str | None = None
    content_text: str | None = None
    video_url: str | None = None
    video_provider: str | None = None
    duration_minutes: int | None = None
    is_required: int | None = None
    position: int | None = None
    quiz_id: int | None = None
    live_session_url: str | None = None
    live_session_start: str | None = None
    live_session_end: str | None = None


class ProgressUpdate(BaseModel):
    status: str | None = None  # not_started, in_progress, completed
    time_spent: int | None = None  # seconds
    score: float | None = None


class AIGenerateRequest(BaseModel):
    model_config = {"protected_namespaces": ()}

    prompt: str
    action: str = "generate"  # generate, refine, summarize
    existing_content: str | None = None
    model_id: str | None = None  # optional override model


# ── Helpers ──────────────────────────────────────────────────────────

def _course_owner_or_admin(course_id: int, current_user: User, db: Session) -> Course:
    course = db.query(Course).filter(Course.id == course_id).first()
    if not course:
        raise HTTPException(status_code=404, detail="Course not found")
    if course.user_id != current_user.id and not current_user.is_admin:
        raise HTTPException(status_code=403, detail="Not your course")
    return course


def _detect_video_provider(url: str | None) -> str | None:
    if not url:
        return None
    lower = url.lower()
    if "vimeo.com" in lower:
        return "vimeo"
    if "youtube.com" in lower or "youtu.be" in lower:
        return "youtube"
    return "local"


def _bbb_checksum(call_name: str, params: str, secret: str) -> str:
    return hashlib.sha1(f"{call_name}{params}{secret}".encode()).hexdigest()


# ── Course CRUD ──────────────────────────────────────────────────────

@router.post("/")
def create_course(
    data: CourseCreate,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """Create a new course (moderators and admins only). Starts as draft."""
    if not current_user.is_moderator:
        raise HTTPException(status_code=403, detail="Only moderators and admins can create courses")
    course = Course(
        title=data.title,
        description=data.description,
        user_id=current_user.id,
        status="draft",
    )
    db.add(course)
    db.commit()
    db.refresh(course)
    return {
        "id": course.id,
        "title": course.title,
        "status": course.status,
        "created_at": course.created_at,
    }


@router.get("/")
def list_courses(
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """List courses. Published visible to all; draft/archived only to creator/admin."""
    enrolled_count_sq = (
        db.query(
            CourseEnrollment.course_id,
            func.count(CourseEnrollment.id).label("enrolled_count"),
        )
        .group_by(CourseEnrollment.course_id)
        .subquery()
    )

    rows = (
        db.query(
            Course,
            func.coalesce(enrolled_count_sq.c.enrolled_count, 0).label("enrolled_count"),
        )
        .outerjoin(enrolled_count_sq, Course.id == enrolled_count_sq.c.course_id)
        .order_by(Course.created_at.desc())
        .all()
    )

    # Pre-fetch module counts
    mod_counts = dict(
        db.query(CourseModule.course_id, func.count(CourseModule.id))
        .group_by(CourseModule.course_id)
        .all()
    )

    user_cache: dict[int, str] = {}
    result = []
    for course, enrolled in rows:
        # Filter: non-published courses only visible to creator or admin
        if course.status != "published":
            if course.user_id != current_user.id and not current_user.is_admin:
                continue

        if course.user_id not in user_cache:
            owner = db.query(User).filter(User.id == course.user_id).first()
            user_cache[course.user_id] = owner.name if owner else "Unknown"

        result.append({
            "id": course.id,
            "title": course.title,
            "description": course.description,
            "status": course.status,
            "thumbnail_path": course.thumbnail_path,
            "requires_subscription": course.requires_subscription,
            "user_id": course.user_id,
            "creator_name": user_cache[course.user_id],
            "enrolled_count": int(enrolled),
            "module_count": mod_counts.get(course.id, 0),
            "created_at": course.created_at,
            "updated_at": course.updated_at,
        })

    return result


@router.get("/published")
def list_published_courses(
    limit: int = Query(20, le=100),
    offset: int = Query(0),
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """List only published courses (for students browsing). Paginated."""
    enrolled_count_sq = (
        db.query(
            CourseEnrollment.course_id,
            func.count(CourseEnrollment.id).label("enrolled_count"),
        )
        .group_by(CourseEnrollment.course_id)
        .subquery()
    )

    total = db.query(Course).filter(Course.status == "published").count()

    rows = (
        db.query(
            Course,
            func.coalesce(enrolled_count_sq.c.enrolled_count, 0).label("enrolled_count"),
        )
        .outerjoin(enrolled_count_sq, Course.id == enrolled_count_sq.c.course_id)
        .filter(Course.status == "published")
        .order_by(Course.created_at.desc())
        .offset(offset)
        .limit(limit)
        .all()
    )

    # Pre-fetch module counts
    course_ids = [c.id for c, _ in rows]
    mod_counts = dict(
        db.query(CourseModule.course_id, func.count(CourseModule.id))
        .filter(CourseModule.course_id.in_(course_ids))
        .group_by(CourseModule.course_id)
        .all()
    ) if course_ids else {}

    # Check which courses current user is enrolled in
    my_enrolled_ids = set(
        db.query(CourseEnrollment.course_id)
        .filter(CourseEnrollment.user_id == current_user.id, CourseEnrollment.course_id.in_(course_ids))
        .all()
    )
    my_enrolled_ids = {row[0] for row in my_enrolled_ids}

    user_cache: dict[int, str] = {}
    courses = []
    for course, enrolled in rows:
        if course.user_id not in user_cache:
            owner = db.query(User).filter(User.id == course.user_id).first()
            user_cache[course.user_id] = owner.name if owner else "Unknown"
        courses.append({
            "id": course.id,
            "title": course.title,
            "description": course.description,
            "thumbnail_path": course.thumbnail_path,
            "requires_subscription": course.requires_subscription,
            "user_id": course.user_id,
            "creator_name": user_cache[course.user_id],
            "enrolled_count": int(enrolled),
            "module_count": mod_counts.get(course.id, 0),
            "is_enrolled": course.id in my_enrolled_ids,
            "created_at": course.created_at,
        })

    return {"total": total, "courses": courses}


@router.get("/my-courses")
def my_courses(
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """List courses the current user is enrolled in, with progress."""
    enrollments = (
        db.query(CourseEnrollment)
        .filter(CourseEnrollment.user_id == current_user.id)
        .all()
    )

    course_ids = [e.course_id for e in enrollments]
    mod_counts = dict(
        db.query(CourseModule.course_id, func.count(CourseModule.id))
        .filter(CourseModule.course_id.in_(course_ids))
        .group_by(CourseModule.course_id)
        .all()
    ) if course_ids else {}

    result = []
    for enrollment in enrollments:
        course = db.query(Course).filter(Course.id == enrollment.course_id).first()
        if not course:
            continue
        owner = db.query(User).filter(User.id == course.user_id).first()
        result.append({
            "id": course.id,
            "title": course.title,
            "description": course.description,
            "thumbnail_path": course.thumbnail_path,
            "status": course.status,
            "creator_name": owner.name if owner else "Unknown",
            "module_count": mod_counts.get(course.id, 0),
            "enrollment_id": enrollment.id,
            "progress_pct": enrollment.progress_pct,
            "enrolled_at": enrollment.enrolled_at,
            "completed_at": enrollment.completed_at,
        })

    return result


def _build_lesson_dict(les, db, user_id):
    """Build lesson dict with quiz metadata if applicable."""
    d = {
        "id": les.id,
        "title": les.title,
        "lesson_type": les.lesson_type,
        "content_text": les.content_text,
        "video_url": les.video_url,
        "video_provider": les.video_provider,
        "local_file_path": les.local_file_path,
        "duration_minutes": les.duration_minutes,
        "quiz_id": les.quiz_id,
        "live_session_url": les.live_session_url,
        "live_session_start": les.live_session_start,
        "live_session_end": les.live_session_end,
        "description": les.description,
        "is_required": les.is_required,
        "position": les.position,
        "bbb_meeting_id": les.bbb_meeting_id,
    }
    # Add quiz info for quiz lessons
    if les.quiz_id and les.lesson_type == "quiz":
        from app.models.attempt import QuizAttempt
        quiz = db.query(Quiz).filter(Quiz.id == les.quiz_id).first()
        if quiz:
            attempts = (
                db.query(QuizAttempt)
                .filter(QuizAttempt.quiz_id == quiz.id, QuizAttempt.user_id == user_id)
                .order_by(QuizAttempt.completed_at.desc())
                .all()
            )
            d["quiz_title"] = quiz.title
            d["quiz_allow_review"] = quiz.allow_review
            d["quiz_mode"] = quiz.mode
            d["quiz_time_limit"] = quiz.time_limit_minutes
            d["quiz_max_attempts"] = quiz.max_attempts
            d["quiz_questions_count"] = quiz.questions_count
            d["quiz_questions_per_attempt"] = quiz.questions_per_attempt
            d["quiz_attempts"] = [
                {
                    "id": a.id,
                    "score": a.score,
                    "total": a.total_questions,
                    "percentage": round(a.score / a.total_questions * 100) if a.total_questions else 0,
                    "completed_at": a.completed_at.isoformat() if a.completed_at else None,
                }
                for a in attempts
            ]
    return d


@router.get("/{course_id}")
def get_course(
    course_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """Full course detail with modules and lessons. Includes enrollment progress if enrolled."""
    course = db.query(Course).filter(Course.id == course_id).first()
    if not course:
        raise HTTPException(status_code=404, detail="Course not found")

    # Non-published courses only visible to creator or admin
    if course.status != "published":
        if course.user_id != current_user.id and not current_user.is_admin:
            raise HTTPException(status_code=404, detail="Course not found")

    # Creator info
    owner = db.query(User).filter(User.id == course.user_id).first()
    creator_name = owner.name if owner else "Unknown"

    # Enrolled count
    enrolled_count = (
        db.query(func.count(CourseEnrollment.id))
        .filter(CourseEnrollment.course_id == course_id)
        .scalar()
    )

    # Modules + lessons
    modules = (
        db.query(CourseModule)
        .filter(CourseModule.course_id == course_id)
        .order_by(CourseModule.position, CourseModule.id)
        .all()
    )
    modules_out = []
    for mod in modules:
        lessons = (
            db.query(CourseLesson)
            .filter(CourseLesson.module_id == mod.id)
            .order_by(CourseLesson.position, CourseLesson.id)
            .all()
        )
        modules_out.append({
            "id": mod.id,
            "title": mod.title,
            "description": mod.description,
            "position": mod.position,
            "lessons": [
                _build_lesson_dict(les, db, current_user.id)
                for les in lessons
            ],
        })

    # My enrollment + progress
    my_enrollment = None
    enrollment = (
        db.query(CourseEnrollment)
        .filter(
            CourseEnrollment.course_id == course_id,
            CourseEnrollment.user_id == current_user.id,
        )
        .first()
    )
    if enrollment:
        lesson_progress = (
            db.query(CourseLessonProgress)
            .filter(CourseLessonProgress.enrollment_id == enrollment.id)
            .all()
        )
        my_enrollment = {
            "enrollment_id": enrollment.id,
            "progress_pct": enrollment.progress_pct,
            "enrolled_at": enrollment.enrolled_at,
            "completed_at": enrollment.completed_at,
            "lesson_progress": {
                lp.lesson_id: {
                    "status": lp.status,
                    "time_spent": lp.time_spent_seconds,
                    "score": lp.score,
                    "completed_at": lp.completed_at,
                }
                for lp in lesson_progress
            },
        }

    return {
        "id": course.id,
        "title": course.title,
        "description": course.description,
        "status": course.status,
        "thumbnail_path": course.thumbnail_path,
        "requires_subscription": course.requires_subscription,
        "user_id": course.user_id,
        "creator_name": creator_name,
        "enrolled_count": enrolled_count,
        "created_at": course.created_at,
        "updated_at": course.updated_at,
        "modules": modules_out,
        "my_enrollment": my_enrollment,
    }


@router.put("/{course_id}")
def update_course(
    course_id: int,
    data: CourseUpdate,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """Update course metadata (creator or admin)."""
    course = _course_owner_or_admin(course_id, current_user, db)
    for field, value in data.model_dump(exclude_unset=True).items():
        setattr(course, field, value)
    course.updated_at = datetime.utcnow()
    db.commit()
    db.refresh(course)
    return {
        "id": course.id,
        "title": course.title,
        "description": course.description,
        "status": course.status,
        "updated_at": course.updated_at,
    }


@router.delete("/{course_id}", status_code=204)
def delete_course(
    course_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """Delete a course (creator or admin)."""
    course = _course_owner_or_admin(course_id, current_user, db)
    db.delete(course)
    db.commit()


@router.post("/{course_id}/publish")
def publish_course(
    course_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """Set course status to published (creator or admin)."""
    course = _course_owner_or_admin(course_id, current_user, db)
    course.status = "published"
    course.updated_at = datetime.utcnow()
    db.commit()
    return {"id": course.id, "status": course.status}


@router.post("/{course_id}/unpublish")
def unpublish_course(
    course_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """Set course status back to draft (creator or admin)."""
    course = _course_owner_or_admin(course_id, current_user, db)
    course.status = "draft"
    course.updated_at = datetime.utcnow()
    db.commit()
    return {"id": course.id, "status": course.status}


@router.post("/{course_id}/thumbnail")
async def upload_thumbnail(
    course_id: int,
    file: UploadFile = File(...),
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """Upload a thumbnail image for a course (creator or admin)."""
    course = _course_owner_or_admin(course_id, current_user, db)

    # Validate content type
    if not file.content_type or not file.content_type.startswith("image/"):
        raise HTTPException(status_code=400, detail="File must be an image")

    upload_dir = os.path.join(settings.UPLOAD_DIR, "course_thumbnails")
    os.makedirs(upload_dir, exist_ok=True)

    ext = os.path.splitext(file.filename or "img.jpg")[1] or ".jpg"
    filename = f"{course_id}_{uuid.uuid4().hex[:8]}{ext}"
    file_path = os.path.join(upload_dir, filename)

    contents = await file.read()
    with open(file_path, "wb") as f:
        f.write(contents)

    course.thumbnail_path = f"/uploads/course_thumbnails/{filename}"
    course.updated_at = datetime.utcnow()
    db.commit()

    return {"thumbnail_path": course.thumbnail_path}


# ── Module CRUD ──────────────────────────────────────────────────────

@router.post("/{course_id}/modules")
def create_module(
    course_id: int,
    data: ModuleCreate,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """Add a module to a course (creator or admin)."""
    _course_owner_or_admin(course_id, current_user, db)

    # Auto position if not provided
    position = data.position
    if position is None:
        max_order = (
            db.query(func.max(CourseModule.position))
            .filter(CourseModule.course_id == course_id)
            .scalar()
        )
        position = (max_order or 0) + 1

    module = CourseModule(
        course_id=course_id,
        title=data.title,
        description=data.description,
        position=position,
    )
    db.add(module)
    db.commit()
    db.refresh(module)
    return {
        "id": module.id,
        "course_id": module.course_id,
        "title": module.title,
        "description": module.description,
        "position": module.position,
    }


@router.put("/{course_id}/modules/{module_id}")
def update_module(
    course_id: int,
    module_id: int,
    data: ModuleUpdate,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """Update a module (creator or admin)."""
    _course_owner_or_admin(course_id, current_user, db)
    module = (
        db.query(CourseModule)
        .filter(CourseModule.id == module_id, CourseModule.course_id == course_id)
        .first()
    )
    if not module:
        raise HTTPException(status_code=404, detail="Module not found")
    for field, value in data.model_dump(exclude_unset=True).items():
        setattr(module, field, value)
    db.commit()
    db.refresh(module)
    return {
        "id": module.id,
        "title": module.title,
        "description": module.description,
        "position": module.position,
    }


@router.delete("/{course_id}/modules/{module_id}", status_code=204)
def delete_module(
    course_id: int,
    module_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """Delete a module and its lessons (creator or admin)."""
    _course_owner_or_admin(course_id, current_user, db)
    module = (
        db.query(CourseModule)
        .filter(CourseModule.id == module_id, CourseModule.course_id == course_id)
        .first()
    )
    if not module:
        raise HTTPException(status_code=404, detail="Module not found")
    db.delete(module)
    db.commit()


@router.put("/{course_id}/modules/reorder")
def reorder_modules(
    course_id: int,
    data: ModuleReorder,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """Reorder modules by providing list of module IDs in desired order."""
    _course_owner_or_admin(course_id, current_user, db)
    for idx, mod_id in enumerate(data.module_ids):
        module = (
            db.query(CourseModule)
            .filter(CourseModule.id == mod_id, CourseModule.course_id == course_id)
            .first()
        )
        if module:
            module.position = idx + 1
    db.commit()
    return {"reordered": True, "count": len(data.module_ids)}


class LessonReorder(BaseModel):
    lesson_ids: list[int]


@router.put("/{course_id}/modules/{module_id}/lessons/reorder")
def reorder_lessons(
    course_id: int,
    module_id: int,
    data: LessonReorder,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """Reorder lessons within a module by providing list of lesson IDs in desired order."""
    _course_owner_or_admin(course_id, current_user, db)
    for idx, lesson_id in enumerate(data.lesson_ids):
        lesson = (
            db.query(CourseLesson)
            .filter(CourseLesson.id == lesson_id, CourseLesson.module_id == module_id)
            .first()
        )
        if lesson:
            lesson.position = idx + 1
    db.commit()
    return {"reordered": True, "count": len(data.lesson_ids)}


# ── Course Quiz Creation ─────────────────────────────────────────────

class CourseQuizCreate(BaseModel):
    question_ids: list[int]
    title: str | None = None
    mode: str = "learning"  # timed or learning
    time_limit_minutes: int | None = None
    max_attempts: int | None = None  # null = unlimited
    questions_per_attempt: int | None = None  # null = all questions; set to pick random subset
    allow_review: bool = True  # whether students can review answers after submit


@router.post("/{course_id}/quiz")
def create_course_quiz(
    course_id: int,
    data: CourseQuizCreate,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """Create a course-only quiz by copying selected questions. The quiz and copies
    are independent from the main question bank and quiz list."""
    _course_owner_or_admin(course_id, current_user, db)

    if not data.question_ids:
        raise HTTPException(status_code=400, detail="Select at least one question")

    source_questions = db.query(Question).filter(Question.id.in_(data.question_ids)).all()
    if not source_questions:
        raise HTTPException(status_code=404, detail="No valid questions found")

    # Preserve caller order
    id_order = {qid: i for i, qid in enumerate(data.question_ids)}
    source_questions.sort(key=lambda q: id_order.get(q.id, 999))

    # Create quiz tied to this course
    qpa = data.questions_per_attempt
    if qpa and qpa > len(source_questions):
        qpa = None  # can't ask for more than the pool

    quiz = Quiz(
        user_id=current_user.id,
        title=data.title or f"Course Quiz ({len(source_questions)} questions)",
        questions_count=len(source_questions),
        mode=data.mode if data.mode in ("timed", "learning") else "learning",
        time_limit_minutes=data.time_limit_minutes,
        max_attempts=data.max_attempts,
        questions_per_attempt=qpa,
        allow_review=1 if data.allow_review else 0,
        is_published=0,
        is_shared=0,
        course_id=course_id,
    )
    db.add(quiz)
    db.flush()

    # Copy each question (independent copies)
    from app.models.quiz_question_link import QuizQuestionLink
    for pos, sq in enumerate(source_questions):
        copy = Question(
            question_text=sq.question_text,
            question_type=sq.question_type,
            options=sq.options,
            correct_answer=sq.correct_answer,
            explanation=sq.explanation,
            image_path=sq.image_path,
            question_category_id=sq.question_category_id,
            source_quiz_id=quiz.id,
            user_id=current_user.id,
            is_shared=0,
        )
        db.add(copy)
        db.flush()
        db.add(QuizQuestionLink(quiz_id=quiz.id, question_id=copy.id, position=pos))

    quiz.questions_count = len(source_questions)
    db.commit()
    db.refresh(quiz)
    return {"id": quiz.id, "title": quiz.title, "questions_count": quiz.questions_count}


# ── Lesson CRUD ──────────────────────────────────────────────────────

@router.post("/{course_id}/modules/{module_id}/lessons")
def create_lesson(
    course_id: int,
    module_id: int,
    data: LessonCreate,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """Add a lesson to a module (creator or admin). Auto-detects video provider."""
    _course_owner_or_admin(course_id, current_user, db)

    module = (
        db.query(CourseModule)
        .filter(CourseModule.id == module_id, CourseModule.course_id == course_id)
        .first()
    )
    if not module:
        raise HTTPException(status_code=404, detail="Module not found")

    # Auto position if not provided
    position = data.position
    if position is None:
        max_order = (
            db.query(func.max(CourseLesson.position))
            .filter(CourseLesson.module_id == module_id)
            .scalar()
        )
        position = (max_order or 0) + 1

    video_provider = _detect_video_provider(data.video_url)

    lesson = CourseLesson(
        module_id=module_id,
        title=data.title,
        lesson_type=data.lesson_type,
        content_text=data.content_text,
        video_url=data.video_url,
        video_provider=video_provider,
        quiz_id=data.quiz_id,
        live_session_url=data.live_session_url,
        live_session_start=data.live_session_start,
        live_session_end=data.live_session_end,
        duration_minutes=data.duration_minutes,
        is_required=data.is_required,
        position=position,
    )
    db.add(lesson)
    db.commit()
    db.refresh(lesson)
    return {
        "id": lesson.id,
        "module_id": lesson.module_id,
        "title": lesson.title,
        "lesson_type": lesson.lesson_type,
        "video_url": lesson.video_url,
        "video_provider": lesson.video_provider,
        "position": lesson.position,
    }


@router.put("/{course_id}/lessons/{lesson_id}")
def update_lesson(
    course_id: int,
    lesson_id: int,
    data: LessonUpdate,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """Update a lesson (creator or admin)."""
    _course_owner_or_admin(course_id, current_user, db)
    lesson = (
        db.query(CourseLesson)
        .join(CourseModule, CourseLesson.module_id == CourseModule.id)
        .filter(CourseLesson.id == lesson_id, CourseModule.course_id == course_id)
        .first()
    )
    if not lesson:
        raise HTTPException(status_code=404, detail="Lesson not found")

    updates = data.model_dump(exclude_unset=True)
    # Re-detect video provider if video_url changed
    if "video_url" in updates and "video_provider" not in updates:
        updates["video_provider"] = _detect_video_provider(updates["video_url"])

    for field, value in updates.items():
        setattr(lesson, field, value)
    db.commit()
    db.refresh(lesson)
    return {
        "id": lesson.id,
        "title": lesson.title,
        "lesson_type": lesson.lesson_type,
        "video_url": lesson.video_url,
        "video_provider": lesson.video_provider,
        "position": lesson.position,
    }


@router.delete("/{course_id}/lessons/{lesson_id}", status_code=204)
def delete_lesson(
    course_id: int,
    lesson_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """Delete a lesson (creator or admin)."""
    _course_owner_or_admin(course_id, current_user, db)
    lesson = (
        db.query(CourseLesson)
        .join(CourseModule, CourseLesson.module_id == CourseModule.id)
        .filter(CourseLesson.id == lesson_id, CourseModule.course_id == course_id)
        .first()
    )
    if not lesson:
        raise HTTPException(status_code=404, detail="Lesson not found")
    db.delete(lesson)
    db.commit()


@router.post("/{course_id}/lessons/{lesson_id}/upload")
async def upload_lesson_file(
    course_id: int,
    lesson_id: int,
    file: UploadFile = File(...),
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """Upload a video or document file for a lesson (creator or admin)."""
    _course_owner_or_admin(course_id, current_user, db)
    lesson = (
        db.query(CourseLesson)
        .join(CourseModule, CourseLesson.module_id == CourseModule.id)
        .filter(CourseLesson.id == lesson_id, CourseModule.course_id == course_id)
        .first()
    )
    if not lesson:
        raise HTTPException(status_code=404, detail="Lesson not found")

    upload_dir = os.path.join(settings.UPLOAD_DIR, "course_files", str(course_id))
    os.makedirs(upload_dir, exist_ok=True)

    ext = os.path.splitext(file.filename or "file")[1]
    filename = f"{lesson_id}_{uuid.uuid4().hex[:8]}{ext}"
    file_path = os.path.join(upload_dir, filename)

    contents = await file.read()
    if len(contents) > settings.MAX_UPLOAD_SIZE:
        raise HTTPException(status_code=413, detail="File too large")

    with open(file_path, "wb") as f:
        f.write(contents)

    lesson.local_file_path = f"/uploads/course_files/{course_id}/{filename}"
    if not lesson.video_url:
        lesson.video_provider = "local"
    db.commit()

    return {"local_file_path": lesson.local_file_path}


# ── SCORM ────────────────────────────────────────────────────────────

@router.post("/{course_id}/lessons/{lesson_id}/scorm")
async def upload_scorm_package(
    course_id: int,
    lesson_id: int,
    file: UploadFile = File(...),
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """Upload a SCORM package (ZIP) for a lesson."""
    import zipfile
    import xml.etree.ElementTree as ET

    _course_owner_or_admin(course_id, current_user, db)
    lesson = (
        db.query(CourseLesson)
        .join(CourseModule, CourseLesson.module_id == CourseModule.id)
        .filter(CourseLesson.id == lesson_id, CourseModule.course_id == course_id)
        .first()
    )
    if not lesson:
        raise HTTPException(status_code=404, detail="Lesson not found")

    if not file.filename or not file.filename.lower().endswith(".zip"):
        raise HTTPException(status_code=400, detail="SCORM package must be a ZIP file")

    contents = await file.read()
    if len(contents) > 200 * 1024 * 1024:  # 200MB limit for SCORM
        raise HTTPException(status_code=413, detail="SCORM package too large (max 200MB)")

    # Extract to scorm directory
    scorm_dir = os.path.join(settings.UPLOAD_DIR, "scorm", str(course_id), str(lesson_id))
    if os.path.exists(scorm_dir):
        import shutil
        shutil.rmtree(scorm_dir)
    os.makedirs(scorm_dir, exist_ok=True)

    import io
    try:
        with zipfile.ZipFile(io.BytesIO(contents)) as zf:
            zf.extractall(scorm_dir)
    except zipfile.BadZipFile:
        raise HTTPException(status_code=400, detail="Invalid ZIP file")

    # Parse imsmanifest.xml to find launch file
    manifest_path = os.path.join(scorm_dir, "imsmanifest.xml")
    if not os.path.exists(manifest_path):
        import shutil
        shutil.rmtree(scorm_dir)
        raise HTTPException(status_code=400, detail="Not a valid SCORM package — missing imsmanifest.xml")

    launch_file = None
    try:
        tree = ET.parse(manifest_path)
        root = tree.getroot()
        ns = {"": root.tag.split("}")[0] + "}"} if "}" in root.tag else {}
        prefix = ns.get("", "")
        # Find first resource with href
        for resource in root.iter(f"{prefix}resource"):
            href = resource.get("href")
            if href:
                launch_file = href
                break
    except Exception:
        logger.warning("Failed to parse SCORM manifest for lesson %d", lesson_id, exc_info=True)

    if not launch_file:
        launch_file = "index.html"  # fallback

    scorm_url = f"/uploads/scorm/{course_id}/{lesson_id}"
    lesson.local_file_path = f"{scorm_url}/{launch_file}"
    lesson.lesson_type = "scorm_package"
    db.commit()

    return {
        "scorm_url": scorm_url,
        "launch_file": launch_file,
        "full_url": f"{scorm_url}/{launch_file}",
    }


@router.get("/{course_id}/lessons/{lesson_id}/scorm/status")
def get_scorm_status(
    course_id: int,
    lesson_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """Get SCORM completion status for this user/lesson."""
    enrollment = db.query(CourseEnrollment).filter(
        CourseEnrollment.course_id == course_id,
        CourseEnrollment.user_id == current_user.id,
    ).first()
    if not enrollment:
        return {"completed": False}
    progress = (
        db.query(CourseLessonProgress)
        .filter(CourseLessonProgress.enrollment_id == enrollment.id, CourseLessonProgress.lesson_id == lesson_id)
        .first()
    )
    return {"completed": progress.status == "completed" if progress else False}


@router.get("/{course_id}/lessons/{lesson_id}/scorm/data")
def get_scorm_data(
    course_id: int,
    lesson_id: int,
    current_user: User = Depends(get_current_user),
):
    """Get saved SCORM runtime data for this user/lesson."""
    import json
    try:
        import redis as redis_lib
        r = redis_lib.from_url(settings.REDIS_URL, decode_responses=True)
        key = f"scorm_data:{current_user.id}:{course_id}:{lesson_id}"
        data = r.get(key)
        return json.loads(data) if data else {}
    except Exception:
        logger.warning("Redis unavailable for SCORM data retrieval", exc_info=True)
        return {}


@router.put("/{course_id}/lessons/{lesson_id}/scorm/data")
def save_scorm_data(
    course_id: int,
    lesson_id: int,
    data: dict,
    current_user: User = Depends(get_current_user),
):
    """Save SCORM runtime data for this user/lesson. Persists bookmarks, scores, and state."""
    import json
    try:
        import redis as redis_lib
        r = redis_lib.from_url(settings.REDIS_URL, decode_responses=True)
        key = f"scorm_data:{current_user.id}:{course_id}:{lesson_id}"
        r.set(key, json.dumps(data), ex=60 * 60 * 24 * 90)  # 90 day expiry
        return {"saved": True}
    except Exception:
        raise HTTPException(status_code=500, detail="Failed to save SCORM data")


# ── Enrollment ───────────────────────────────────────────────────────

@router.get("/{course_id}/enrollees")
def list_enrollees(
    course_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """List all enrollees with progress and quiz scores. Creator or admin only."""
    course = _course_owner_or_admin(course_id, current_user, db)

    enrollments = (
        db.query(CourseEnrollment)
        .filter(CourseEnrollment.course_id == course_id)
        .all()
    )

    # Get all quiz lessons for this course
    from app.models.attempt import QuizAttempt
    quiz_lessons = (
        db.query(CourseLesson)
        .join(CourseModule, CourseLesson.module_id == CourseModule.id)
        .filter(CourseModule.course_id == course_id, CourseLesson.lesson_type == "quiz", CourseLesson.quiz_id.isnot(None))
        .all()
    )
    quiz_ids = [l.quiz_id for l in quiz_lessons]
    quiz_titles = {}
    for l in quiz_lessons:
        q = db.query(Quiz).filter(Quiz.id == l.quiz_id).first()
        quiz_titles[l.quiz_id] = q.title if q else l.title

    result = []
    for enrollment in enrollments:
        user = db.query(User).filter(User.id == enrollment.user_id).first()
        if not user:
            continue

        # Lesson progress
        lesson_progress = (
            db.query(CourseLessonProgress)
            .filter(CourseLessonProgress.enrollment_id == enrollment.id)
            .all()
        )
        completed_count = sum(1 for lp in lesson_progress if lp.status == "completed")

        # Quiz scores
        quiz_scores = []
        for qid in quiz_ids:
            best = (
                db.query(QuizAttempt)
                .filter(QuizAttempt.quiz_id == qid, QuizAttempt.user_id == enrollment.user_id, QuizAttempt.completed_at.isnot(None))
                .order_by(QuizAttempt.score.desc())
                .first()
            )
            if best:
                quiz_scores.append({
                    "quiz_id": qid,
                    "quiz_title": quiz_titles.get(qid, f"Quiz {qid}"),
                    "best_score": best.score,
                    "total": best.total_questions,
                    "percentage": round(best.score / best.total_questions * 100) if best.total_questions else 0,
                    "attempts": db.query(func.count(QuizAttempt.id)).filter(
                        QuizAttempt.quiz_id == qid, QuizAttempt.user_id == enrollment.user_id, QuizAttempt.completed_at.isnot(None)
                    ).scalar(),
                })

        result.append({
            "user_id": enrollment.user_id,
            "name": user.name,
            "email": user.email,
            "progress_pct": enrollment.progress_pct or 0,
            "completed_lessons": completed_count,
            "enrolled_at": enrollment.enrolled_at,
            "completed_at": enrollment.completed_at,
            "quiz_scores": quiz_scores,
        })

    return result


@router.get("/{course_id}/enrollees/export")
def export_enrollees_csv(
    course_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """Export enrollee data as CSV. Creator or admin only."""
    import csv as csv_mod
    import io as io_mod
    from fastapi.responses import StreamingResponse
    from app.models.attempt import QuizAttempt

    course = _course_owner_or_admin(course_id, current_user, db)

    enrollments = db.query(CourseEnrollment).filter(CourseEnrollment.course_id == course_id).all()

    quiz_lessons = (
        db.query(CourseLesson)
        .join(CourseModule, CourseLesson.module_id == CourseModule.id)
        .filter(CourseModule.course_id == course_id, CourseLesson.lesson_type == "quiz", CourseLesson.quiz_id.isnot(None))
        .all()
    )
    quiz_ids = [l.quiz_id for l in quiz_lessons]
    quiz_titles = {}
    for l in quiz_lessons:
        q = db.query(Quiz).filter(Quiz.id == l.quiz_id).first()
        quiz_titles[l.quiz_id] = q.title if q else l.title

    buf = io_mod.StringIO()
    writer = csv_mod.writer(buf)

    # Header
    header = ["Name", "Email", "Progress %", "Completed Lessons", "Enrolled Date", "Completed Date"]
    for qid in quiz_ids:
        header.append(f"Quiz: {quiz_titles.get(qid, qid)} (Best %)")
        header.append(f"Quiz: {quiz_titles.get(qid, qid)} (Attempts)")
    writer.writerow(header)

    for enrollment in enrollments:
        user = db.query(User).filter(User.id == enrollment.user_id).first()
        if not user:
            continue
        lp_count = db.query(func.count(CourseLessonProgress.id)).filter(
            CourseLessonProgress.enrollment_id == enrollment.id, CourseLessonProgress.status == "completed"
        ).scalar()

        row = [
            user.name, user.email,
            enrollment.progress_pct or 0,
            lp_count,
            enrollment.enrolled_at.strftime("%Y-%m-%d") if enrollment.enrolled_at else "",
            enrollment.completed_at.strftime("%Y-%m-%d") if enrollment.completed_at else "",
        ]
        for qid in quiz_ids:
            best = (
                db.query(QuizAttempt)
                .filter(QuizAttempt.quiz_id == qid, QuizAttempt.user_id == enrollment.user_id, QuizAttempt.completed_at.isnot(None))
                .order_by(QuizAttempt.score.desc())
                .first()
            )
            if best:
                row.append(round(best.score / best.total_questions * 100) if best.total_questions else 0)
                row.append(db.query(func.count(QuizAttempt.id)).filter(
                    QuizAttempt.quiz_id == qid, QuizAttempt.user_id == enrollment.user_id, QuizAttempt.completed_at.isnot(None)
                ).scalar())
            else:
                row.append("")
                row.append(0)
        writer.writerow(row)

    buf.seek(0)
    # Add UTF-8 BOM for LibreOffice/Excel compatibility
    csv_content = "\ufeff" + buf.getvalue()
    filename = f"{course.title.replace(' ', '_')}_enrollees.csv"
    return StreamingResponse(
        iter([csv_content]),
        media_type="text/csv; charset=utf-8",
        headers={"Content-Disposition": f"attachment; filename={filename}"},
    )


@router.post("/{course_id}/enroll")
def enroll(
    course_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """Enroll in a published course."""
    course = db.query(Course).filter(Course.id == course_id).first()
    if not course:
        raise HTTPException(status_code=404, detail="Course not found")
    if course.status != "published":
        raise HTTPException(status_code=400, detail="Course is not published")

    # Subscription gate (placeholder for future Stripe)
    if course.requires_subscription:
        raise HTTPException(status_code=402, detail="This course requires a subscription")

    # No double enrollment
    existing = (
        db.query(CourseEnrollment)
        .filter(
            CourseEnrollment.course_id == course_id,
            CourseEnrollment.user_id == current_user.id,
        )
        .first()
    )
    if existing:
        raise HTTPException(status_code=409, detail="Already enrolled")

    enrollment = CourseEnrollment(
        course_id=course_id,
        user_id=current_user.id,
    )
    db.add(enrollment)
    db.commit()
    db.refresh(enrollment)
    return {
        "enrollment_id": enrollment.id,
        "course_id": course_id,
        "enrolled_at": enrollment.enrolled_at,
    }


@router.delete("/{course_id}/enroll", status_code=204)
def unenroll(
    course_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """Unenroll from a course."""
    enrollment = (
        db.query(CourseEnrollment)
        .filter(
            CourseEnrollment.course_id == course_id,
            CourseEnrollment.user_id == current_user.id,
        )
        .first()
    )
    if not enrollment:
        raise HTTPException(status_code=404, detail="Not enrolled")
    db.delete(enrollment)
    db.commit()


# ── Progress tracking ────────────────────────────────────────────────

@router.put("/{course_id}/lessons/{lesson_id}/progress")
def update_progress(
    course_id: int,
    lesson_id: int,
    data: ProgressUpdate,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """Update lesson progress. Auto-calculates enrollment progress_pct."""
    enrollment = (
        db.query(CourseEnrollment)
        .filter(
            CourseEnrollment.course_id == course_id,
            CourseEnrollment.user_id == current_user.id,
        )
        .first()
    )
    if not enrollment:
        raise HTTPException(status_code=403, detail="Not enrolled in this course")

    # Verify lesson belongs to this course
    lesson = (
        db.query(CourseLesson)
        .join(CourseModule, CourseLesson.module_id == CourseModule.id)
        .filter(CourseLesson.id == lesson_id, CourseModule.course_id == course_id)
        .first()
    )
    if not lesson:
        raise HTTPException(status_code=404, detail="Lesson not found in this course")

    # Upsert lesson progress
    progress = (
        db.query(CourseLessonProgress)
        .filter(
            CourseLessonProgress.enrollment_id == enrollment.id,
            CourseLessonProgress.lesson_id == lesson_id,
        )
        .first()
    )
    if not progress:
        progress = CourseLessonProgress(
            enrollment_id=enrollment.id,
            lesson_id=lesson_id,
        )
        db.add(progress)

    if data.status is not None:
        progress.status = data.status
        if data.status == "completed" and not progress.completed_at:
            progress.completed_at = datetime.utcnow()
    if data.time_spent is not None:
        progress.time_spent_seconds = (progress.time_spent_seconds or 0) + data.time_spent
    if data.score is not None:
        progress.score = data.score

    db.flush()

    # Recalculate enrollment progress_pct
    total_required = (
        db.query(func.count(CourseLesson.id))
        .join(CourseModule, CourseLesson.module_id == CourseModule.id)
        .filter(CourseModule.course_id == course_id, CourseLesson.is_required == 1)
        .scalar()
    ) or 1

    completed_required = (
        db.query(func.count(CourseLessonProgress.id))
        .join(CourseLesson, CourseLessonProgress.lesson_id == CourseLesson.id)
        .join(CourseModule, CourseLesson.module_id == CourseModule.id)
        .filter(
            CourseLessonProgress.enrollment_id == enrollment.id,
            CourseModule.course_id == course_id,
            CourseLesson.is_required == 1,
            CourseLessonProgress.status == "completed",
        )
        .scalar()
    ) or 0

    enrollment.progress_pct = round((completed_required / total_required) * 100, 1)
    if enrollment.progress_pct >= 100 and not enrollment.completed_at:
        enrollment.completed_at = datetime.utcnow()

    db.commit()

    return {
        "lesson_id": lesson_id,
        "status": progress.status,
        "time_spent": progress.time_spent_seconds,
        "score": progress.score,
        "enrollment_progress_pct": enrollment.progress_pct,
    }


# ── Certificate ──────────────────────────────────────────────────────

@router.get("/{course_id}/certificate")
def download_certificate(
    course_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """Generate and return a completion certificate PDF."""
    from starlette.responses import FileResponse

    enrollment = db.query(CourseEnrollment).filter(
        CourseEnrollment.course_id == course_id,
        CourseEnrollment.user_id == current_user.id,
    ).first()
    if not enrollment:
        raise HTTPException(status_code=404, detail="Not enrolled in this course")
    if not enrollment.completed_at:
        raise HTTPException(status_code=400, detail="Course not yet completed")

    course = db.query(Course).filter(Course.id == course_id).first()
    if not course:
        raise HTTPException(status_code=404, detail="Course not found")

    from app.services.certificate_service import generate_certificate
    cert_path = generate_certificate(
        student_name=current_user.name or current_user.email,
        course_title=course.title,
        completed_at=enrollment.completed_at,
        upload_dir=settings.UPLOAD_DIR,
    )

    full_path = os.path.join(settings.UPLOAD_DIR, "certificates", os.path.basename(cert_path))
    return FileResponse(
        full_path,
        media_type="application/pdf",
        filename=f"Certificate - {course.title}.pdf",
    )


# ── AI content generation ────────────────────────────────────────────

@router.post("/{course_id}/ai-generate")
def ai_generate_standalone(
    course_id: int,
    data: AIGenerateRequest,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """Generate content using AI without requiring a saved lesson."""
    _course_owner_or_admin(course_id, current_user, db)

    from app.services.ai_service import get_model_for_task, _proxy_model
    import litellm

    if data.model_id:
        model_id = data.model_id
        # Look up API key for this specific model
        from app.models.ai_model_config import AIModelConfig
        config = db.query(AIModelConfig).filter(AIModelConfig.model_id == data.model_id).first()
        api_key = config.api_key if config else None
    else:
        model_id, api_key = get_model_for_task(db, "teach")

    system_msg = (
        "You are a medical education content specialist for pediatrics. "
        "Generate high-quality lesson content in clean standard markdown. "
        "Use ## for section headings (never # — the title is separate). "
        "Use **bold**, *italic*, - bullet lists, 1. numbered lists, > blockquotes, "
        "and standard markdown tables (| col | col |). "
        "Include learning objectives, key concepts, tables, and clinical pearls. "
        "If the user provides existing content, you can see it and modify/extend it as instructed."
    )
    user_msg = data.prompt
    if data.existing_content:
        user_msg = f"Existing content:\n{data.existing_content}\n\nInstructions: {data.prompt}"

    try:
        kwargs = {"model": _proxy_model(model_id), "messages": [
            {"role": "system", "content": system_msg},
            {"role": "user", "content": user_msg},
        ], "max_tokens": 4000}
        if api_key:
            kwargs["api_key"] = api_key
        elif settings.LITELLM_API_KEY:
            kwargs["api_key"] = settings.LITELLM_API_KEY
        if settings.LITELLM_API_BASE:
            kwargs["api_base"] = settings.LITELLM_API_BASE
        response = litellm.completion(**kwargs)
        return {"generated_content": response.choices[0].message.content, "model_used": model_id}
    except Exception as e:
        logger.error(f"AI generation failed: {e}")
        raise HTTPException(status_code=502, detail="AI generation failed")


@router.post("/{course_id}/lessons/{lesson_id}/ai-generate")
def ai_generate_content(
    course_id: int,
    lesson_id: int,
    data: AIGenerateRequest,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """Generate or refine lesson text content using AI."""
    _course_owner_or_admin(course_id, current_user, db)

    lesson = (
        db.query(CourseLesson)
        .join(CourseModule, CourseLesson.module_id == CourseModule.id)
        .filter(CourseLesson.id == lesson_id, CourseModule.course_id == course_id)
        .first()
    )
    if not lesson:
        raise HTTPException(status_code=404, detail="Lesson not found in this course")

    from app.services.ai_service import get_model_for_task, _proxy_model
    import litellm

    if data.model_id:
        model_id = data.model_id
        from app.models.ai_model_config import AIModelConfig
        config = db.query(AIModelConfig).filter(AIModelConfig.model_id == data.model_id).first()
        api_key = config.api_key if config else None
    else:
        model_id, api_key = get_model_for_task(db, "teach")

    if data.action == "refine" and data.existing_content:
        system_msg = (
            "You are a medical education content specialist. "
            "Refine the following lesson content based on the user's instructions. "
            "Maintain accuracy and a clear, professional tone suitable for medical learners."
        )
        user_msg = (
            f"Lesson title: {lesson.title}\n\n"
            f"Existing content:\n{data.existing_content}\n\n"
            f"Instructions: {data.prompt}"
        )
    elif data.action == "summarize" and data.existing_content:
        system_msg = (
            "You are a medical education content specialist. "
            "Summarize the following lesson content concisely while preserving key medical facts."
        )
        user_msg = (
            f"Lesson title: {lesson.title}\n\n"
            f"Content to summarize:\n{data.existing_content}\n\n"
            f"Additional instructions: {data.prompt}"
        )
    else:
        system_msg = (
            "You are a medical education content specialist for pediatrics. "
            "Generate high-quality lesson content in clean standard markdown. "
            "Use ## for section headings (never # — the title is separate). "
            "Use **bold**, *italic*, - bullet lists, 1. numbered lists, > blockquotes, "
            "and standard markdown tables (| col | col |). "
            "Include learning objectives, key concepts, tables, and clinical pearls. "
            "If the user provides existing content, you can see it and modify/extend it as instructed."
        )
        user_msg = (
            f"Lesson title: {lesson.title}\n\n"
            f"Instructions: {data.prompt}"
        )

    try:
        kwargs = {
            "model": _proxy_model(model_id),
            "messages": [
                {"role": "system", "content": system_msg},
                {"role": "user", "content": user_msg},
            ],
            "max_tokens": 4000,
        }
        if api_key:
            kwargs["api_key"] = api_key
        elif settings.LITELLM_API_KEY:
            kwargs["api_key"] = settings.LITELLM_API_KEY
        if settings.LITELLM_API_BASE:
            kwargs["api_base"] = settings.LITELLM_API_BASE

        response = litellm.completion(**kwargs)
        generated = response.choices[0].message.content
    except Exception as e:
        logger.error(f"AI generation failed: {e}")
        raise HTTPException(status_code=502, detail="AI generation failed")

    return {
        "lesson_id": lesson_id,
        "generated_content": generated,
        "model_used": model_id,
    }


# ── BBB integration ──────────────────────────────────────────────────

@router.post("/{course_id}/lessons/{lesson_id}/bbb/create")
def bbb_create_meeting(
    course_id: int,
    lesson_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """Create a BigBlueButton meeting for a live lesson (creator or admin)."""
    _course_owner_or_admin(course_id, current_user, db)

    lesson = (
        db.query(CourseLesson)
        .join(CourseModule, CourseLesson.module_id == CourseModule.id)
        .filter(CourseLesson.id == lesson_id, CourseModule.course_id == course_id)
        .first()
    )
    if not lesson:
        raise HTTPException(status_code=404, detail="Lesson not found in this course")

    bbb_url = getattr(settings, "BBB_SERVER_URL", None)
    bbb_secret = getattr(settings, "BBB_SECRET", None)
    if not bbb_url or not bbb_secret:
        raise HTTPException(status_code=501, detail="BBB not configured")

    meeting_id = lesson.bbb_meeting_id or f"pedshub-{course_id}-{lesson_id}"
    params = urlencode({
        "name": lesson.title,
        "meetingID": meeting_id,
        "attendeePW": "ap",
        "moderatorPW": "mp",
    })
    checksum = _bbb_checksum("create", params, bbb_secret)
    create_url = f"{bbb_url.rstrip('/')}/api/create?{params}&checksum={checksum}"

    # Call BBB API
    import httpx
    try:
        resp = httpx.get(create_url, timeout=10)
        resp.raise_for_status()
    except Exception as e:
        logger.error(f"BBB create failed: {e}")
        raise HTTPException(status_code=502, detail="Failed to create BBB meeting")

    lesson.bbb_meeting_id = meeting_id
    db.commit()

    return {"meeting_id": meeting_id, "create_url": create_url}


@router.get("/{course_id}/lessons/{lesson_id}/bbb/join")
def bbb_join_meeting(
    course_id: int,
    lesson_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """Generate a BBB join URL for the current user."""
    lesson = (
        db.query(CourseLesson)
        .join(CourseModule, CourseLesson.module_id == CourseModule.id)
        .filter(CourseLesson.id == lesson_id, CourseModule.course_id == course_id)
        .first()
    )
    if not lesson:
        raise HTTPException(status_code=404, detail="Lesson not found in this course")
    if not lesson.bbb_meeting_id:
        raise HTTPException(status_code=400, detail="No BBB meeting created for this lesson")

    # Verify user is enrolled or is the course owner/admin
    course = db.query(Course).filter(Course.id == course_id).first()
    is_owner = course and (course.user_id == current_user.id or current_user.is_admin)
    if not is_owner:
        enrolled = db.query(CourseEnrollment).filter(
            CourseEnrollment.course_id == course_id,
            CourseEnrollment.user_id == current_user.id,
        ).first()
        if not enrolled:
            raise HTTPException(status_code=403, detail="You are not enrolled in this course")

    bbb_url = getattr(settings, "BBB_SERVER_URL", None)
    bbb_secret = getattr(settings, "BBB_SECRET", None)
    if not bbb_url or not bbb_secret:
        raise HTTPException(status_code=501, detail="BBB not configured")

    # Course owner/admin joins as moderator, others as attendee
    is_moderator = is_owner
    password = "mp" if is_moderator else "ap"

    params = urlencode({
        "fullName": current_user.name,
        "meetingID": lesson.bbb_meeting_id,
        "password": password,
    })
    checksum = _bbb_checksum("join", params, bbb_secret)
    join_url = f"{bbb_url.rstrip('/')}/api/join?{params}&checksum={checksum}"

    return {"join_url": join_url}
