from fastapi import APIRouter, HTTPException, Request from app.config import settings from app.models.schemas import InitTaskRequest from app.mqtt.init_dispatcher import InitTaskDispatcher from app.services.course_service import CourseService router = APIRouter(prefix="/api/v1", tags=["courses"]) course_service = CourseService() def _get_dispatcher(request: Request) -> InitTaskDispatcher: return request.app.state.init_dispatcher @router.get("/courses") async def list_courses(): return course_service.get_course_index() @router.get("/courses/base-manifest") async def get_base_courses_manifest(): payloads = course_service.build_base_course_sync_payloads(settings.base_url) return { "scope": "base", "course_count": len(payloads), "courses": payloads, } @router.get("/courses/{course_id}") async def get_course(course_id: str): try: return course_service.get_course(course_id) except FileNotFoundError as exc: raise HTTPException(status_code=404, detail=str(exc)) from exc @router.get("/tasklist") async def get_tasklist(): return course_service.get_tasklist() @router.get("/courses/{course_id}/tasks") async def get_course_tasks(course_id: str): try: return course_service.get_course_task(course_id) except FileNotFoundError as exc: raise HTTPException(status_code=404, detail=str(exc)) from exc @router.get("/courses/{course_id}/manifest") async def get_course_manifest(course_id: str): try: payload = course_service.build_course_task_sync_payload(course_id, settings.base_url) return payload except FileNotFoundError as exc: raise HTTPException(status_code=404, detail=str(exc)) from exc @router.post("/devices/init") async def init_device(request: Request, body: InitTaskRequest): auto_init = request.app.state.auto_init commands, status = auto_init.dispatch_manual_init(body.device_id, force=body.force) return {"device_id": body.device_id, "commands": commands, "status": status} @router.post("/devices/course-init") async def init_course_on_device(request: Request, body: InitTaskRequest): if not body.course_id: raise HTTPException(status_code=400, detail="course_id is required") dispatcher = _get_dispatcher(request) commands = dispatcher.dispatch_course_init(body.device_id, body.course_id) return { "device_id": body.device_id, "course_id": body.course_id, "commands": commands, "status": "dispatched", }