"""HTTP routes for workspace, members, and invitations.""" from uuid import UUID from fastapi import APIRouter, HTTPException, status from app.dependencies import CurrentUserDep, WorkspaceServiceDep from app.models.workspace import ( InvitationResponse, InviteResponse, PersonalDataCreate, PersonalDataResponse, RedeemInviteRequest, WorkspaceCreate, WorkspaceResponse, WorkspaceUpdate, ) from app.utils.errors import InvitationError, NotFoundError, ValidationError router = APIRouter(prefix="/api/workspace", tags=["workspace"]) @router.post("", response_model=WorkspaceResponse, status_code=status.HTTP_201_CREATED) async def create_workspace( payload: WorkspaceCreate, service: WorkspaceServiceDep, _current_user: CurrentUserDep, ) -> WorkspaceResponse: ws = await service.create_workspace(payload.name) return WorkspaceResponse.from_entity(ws) @router.get("/{workspace_id}", response_model=WorkspaceResponse) async def get_workspace( workspace_id: UUID, service: WorkspaceServiceDep, _current_user: CurrentUserDep, ) -> WorkspaceResponse: try: ws = await service.get_workspace(workspace_id) except NotFoundError as exc: raise HTTPException(status.HTTP_404_NOT_FOUND, str(exc)) from exc return WorkspaceResponse.from_entity(ws) @router.put("/{workspace_id}", response_model=WorkspaceResponse) async def update_workspace( workspace_id: UUID, payload: WorkspaceUpdate, service: WorkspaceServiceDep, _current_user: CurrentUserDep, ) -> WorkspaceResponse: try: ws = await service.update_workspace(workspace_id, payload.name, payload.planning_goal) except (NotFoundError, ValidationError) as exc: code = ( status.HTTP_404_NOT_FOUND if isinstance(exc, NotFoundError) else status.HTTP_422_UNPROCESSABLE_ENTITY ) raise HTTPException(code, str(exc)) from exc return WorkspaceResponse.from_entity(ws) @router.get("/{workspace_id}/members", response_model=list[PersonalDataResponse]) async def list_members( workspace_id: UUID, service: WorkspaceServiceDep, _current_user: CurrentUserDep, ) -> list[PersonalDataResponse]: members = await service.list_members(workspace_id) return [ PersonalDataResponse( uuid=m.uuid, workspace_id=m.workspace_id, name=m.name, salary_type=m.salary_type, employment_status=m.employment_status, created_at=m.created_at, ) for m in members ] @router.post( "/{workspace_id}/parents", response_model=PersonalDataResponse, status_code=status.HTTP_201_CREATED, ) async def add_placeholder_parent( workspace_id: UUID, payload: PersonalDataCreate, service: WorkspaceServiceDep, _current_user: CurrentUserDep, ) -> PersonalDataResponse: try: pd = await service.add_placeholder_parent(workspace_id, payload.display_name) except NotFoundError as exc: raise HTTPException(status.HTTP_404_NOT_FOUND, str(exc)) from exc return PersonalDataResponse( uuid=pd.uuid, workspace_id=pd.workspace_id, name=pd.name, salary_type=pd.salary_type, employment_status=pd.employment_status, created_at=pd.created_at, ) @router.post( "/{workspace_id}/invitations", response_model=InviteResponse, status_code=status.HTTP_201_CREATED, ) async def create_invitation( workspace_id: UUID, service: WorkspaceServiceDep, current_user: CurrentUserDep, ) -> InviteResponse: try: raw_token = await service.invite_partner(workspace_id, current_user.id) except NotFoundError as exc: raise HTTPException(status.HTTP_404_NOT_FOUND, str(exc)) from exc return InviteResponse(token=raw_token) # Invitation redemption is workspace-agnostic (token carries workspace info). _inv_router = APIRouter(prefix="/api/invitations", tags=["invitations"]) @_inv_router.post("/redeem", response_model=InvitationResponse) async def redeem_invitation( payload: RedeemInviteRequest, service: WorkspaceServiceDep, current_user: CurrentUserDep, ) -> InvitationResponse: try: inv = await service.redeem_invitation(payload.token, current_user.personal_data_uuid) except (InvitationError, NotFoundError) as exc: raise HTTPException(status.HTTP_400_BAD_REQUEST, str(exc)) from exc return InvitationResponse.from_entity(inv) @_inv_router.delete("/{invitation_id}", status_code=status.HTTP_204_NO_CONTENT) async def revoke_invitation( invitation_id: UUID, service: WorkspaceServiceDep, _current_user: CurrentUserDep, ) -> None: try: await service.revoke_invitation(invitation_id) except (NotFoundError, ValidationError) as exc: code = ( status.HTTP_404_NOT_FOUND if isinstance(exc, NotFoundError) else status.HTTP_422_UNPROCESSABLE_ENTITY ) raise HTTPException(code, str(exc)) from exc