from __future__ import annotations import math from fastapi import APIRouter, Depends, Query, Response, status from app.auth.repository import SessionRecord from app.dependencies import get_rotation_service, require_session from app.rotation.service import RotationService router = APIRouter(prefix="/api/v1", tags=["rotations"]) @router.post("/instances/{instance_id}/rotations", status_code=status.HTTP_202_ACCEPTED) async def rotate_instance( instance_id: str, response: Response, _: SessionRecord = Depends(require_session), service: RotationService = Depends(get_rotation_service), ) -> dict: run = service.start_instance(instance_id) response.headers["Location"] = f"/api/v1/rotations/{run.id}" return {"data": run.to_dict()} @router.post( "/instance-groups/{group_id}/rotations", status_code=status.HTTP_202_ACCEPTED, ) async def rotate_group( group_id: str, response: Response, _: SessionRecord = Depends(require_session), service: RotationService = Depends(get_rotation_service), ) -> dict: run = service.start_group(group_id) response.headers["Location"] = f"/api/v1/rotations/{run.id}" return {"data": run.to_dict()} @router.get("/rotations") def list_rotations( page: int = Query(default=1, ge=1), per_page: int = Query(default=20, ge=1, le=100), instance_id: str | None = Query(default=None), group_id: str | None = Query(default=None), run_status: str | None = Query(default=None, alias="status"), _: SessionRecord = Depends(require_session), service: RotationService = Depends(get_rotation_service), ) -> dict: runs, total = service.list( page, per_page, instance_id=instance_id, group_id=group_id, status=run_status, ) return { "data": runs, "summary": service.history_summary(), "pagination": { "page": page, "per_page": per_page, "total": total, "total_pages": math.ceil(total / per_page) if total else 0, }, } @router.get("/rotations/{run_id}") def get_rotation( run_id: str, _: SessionRecord = Depends(require_session), service: RotationService = Depends(get_rotation_service), ) -> dict: return {"data": service.get(run_id)} @router.post("/rotations/{run_id}/resume", status_code=status.HTTP_202_ACCEPTED) async def resume_rotation( run_id: str, _: SessionRecord = Depends(require_session), service: RotationService = Depends(get_rotation_service), ) -> dict: return {"data": service.resume(run_id).to_dict()} @router.post("/rotations/{run_id}/cancel") def cancel_rotation( run_id: str, _: SessionRecord = Depends(require_session), service: RotationService = Depends(get_rotation_service), ) -> dict: return {"data": service.cancel(run_id).to_dict()}