"""HTTP mapping for explicit repair workflows.""" from typing import Annotated from uuid import UUID from fastapi import APIRouter, Depends, HTTPException, status from app.identity import require_permission from app.repairs.dependencies import get_repair_service from app.repairs.exceptions import ( ControlBoardReplacementActorRequired, InvalidMacAddress, RepairActorRequired, RepairCompletionActorRequired, RepairConflict, RepairMinerNotFound, RepairNotFound, ) from app.repairs.models import ( BeginRepairRequest, ControlBoardReplacementRequest, ControlBoardReplacementResponse, BeginRepairResponse, RepairCompleteRequest, RepairDetailResponse, RepairTimelineResponse, ) from app.repairs.service import RepairService router = APIRouter(prefix="/api/repairs", tags=["repairs"]) control_board_router = APIRouter(prefix="/api/miners", tags=["miners"]) require_repair_create = require_permission("repairs.create") require_repair_read = require_permission("repairs.read") require_repair_complete = require_permission("repairs.complete") require_control_board_replace = require_permission("miners.replace_control_board") RepairServiceDependency = Annotated[ RepairService, Depends(get_repair_service), ] RepairCreateUser = Annotated[dict, Depends(require_repair_create)] RepairReadUser = Annotated[dict, Depends(require_repair_read)] RepairCompleteUser = Annotated[dict, Depends(require_repair_complete)] ControlBoardReplaceUser = Annotated[dict, Depends(require_control_board_replace)] @control_board_router.post( "/{miner_id}/replace-control-board", response_model=ControlBoardReplacementResponse, ) def replace_control_board( miner_id: UUID, request: ControlBoardReplacementRequest, service: RepairServiceDependency, current_user: ControlBoardReplaceUser, ) -> ControlBoardReplacementResponse: try: result = service.replace_control_board( miner_id, request, actor_user_id=UUID(str(current_user["id"])), ) except RepairMinerNotFound as exc: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Miner not found" ) from exc except RepairConflict as exc: raise HTTPException( status_code=status.HTTP_409_CONFLICT, detail=str(exc) ) from exc except (InvalidMacAddress, ControlBoardReplacementActorRequired) as exc: raise HTTPException( status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=str(exc) ) from exc return ControlBoardReplacementResponse(data=result) @router.post( "", response_model=BeginRepairResponse, status_code=status.HTTP_201_CREATED, ) def begin_repair( request: BeginRepairRequest, service: RepairServiceDependency, current_user: RepairCreateUser, ) -> BeginRepairResponse: try: repair = service.begin_repair( request, actor_user_id=UUID(str(current_user["id"])), ) except RepairMinerNotFound as exc: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Miner not found", ) from exc except RepairConflict as exc: raise HTTPException( status_code=status.HTTP_409_CONFLICT, detail=str(exc), ) from exc except RepairActorRequired as exc: raise HTTPException( status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=str(exc), ) from exc return BeginRepairResponse(data=repair) @router.post( "/{repair_id}/complete", response_model=RepairDetailResponse, ) def complete_repair( repair_id: UUID, request: RepairCompleteRequest, service: RepairServiceDependency, current_user: RepairCompleteUser, ) -> RepairDetailResponse: try: repair = service.complete_repair( repair_id, request, actor_user_id=UUID(str(current_user["id"])), ) except RepairNotFound as exc: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Repair not found", ) from exc except RepairMinerNotFound as exc: raise HTTPException( status_code=status.HTTP_409_CONFLICT, detail="Repair miner no longer exists", ) from exc except RepairConflict as exc: raise HTTPException( status_code=status.HTTP_409_CONFLICT, detail=str(exc), ) from exc except RepairCompletionActorRequired as exc: raise HTTPException( status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=str(exc), ) from exc return RepairDetailResponse(data=repair) @router.get( "/{repair_id}", response_model=RepairDetailResponse, ) def get_repair( repair_id: UUID, service: RepairServiceDependency, current_user: RepairReadUser, ) -> RepairDetailResponse: del current_user try: repair = service.get_repair(repair_id) except RepairNotFound as exc: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Repair not found", ) from exc return RepairDetailResponse(data=repair) @router.get( "/{repair_id}/events", response_model=RepairTimelineResponse, ) def get_repair_events( repair_id: UUID, service: RepairServiceDependency, current_user: RepairReadUser, ) -> RepairTimelineResponse: del current_user try: timeline = service.get_repair_timeline(repair_id) except RepairNotFound as exc: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Repair not found", ) from exc return RepairTimelineResponse(data=timeline)