"""Board management API endpoints.""" from typing import Annotated from uuid import UUID from fastapi import APIRouter, Depends, HTTPException, Query, status from sqlalchemy.orm import Session from app.boards.repository import BoardRepository from app.boards.schemas import BoardCreate, BoardDetail, BoardSummary, BoardUpdate, ViewportStateUpdate from app.core.deps import get_current_user, get_db_sync from app.database.models.user import User router = APIRouter(prefix="/boards", tags=["boards"]) @router.post("", response_model=BoardDetail, status_code=status.HTTP_201_CREATED) def create_board( board_data: BoardCreate, current_user: Annotated[User, Depends(get_current_user)], db: Annotated[Session, Depends(get_db_sync)], ): """ Create a new board. Args: board_data: Board creation data current_user: Current authenticated user db: Database session Returns: Created board details """ repo = BoardRepository(db) board = repo.create_board( user_id=current_user.id, title=board_data.title, description=board_data.description, ) return BoardDetail.model_validate(board) @router.get("", response_model=dict) def list_boards( current_user: Annotated[User, Depends(get_current_user)], db: Annotated[Session, Depends(get_db_sync)], limit: Annotated[int, Query(ge=1, le=100)] = 50, offset: Annotated[int, Query(ge=0)] = 0, ): """ List all boards for the current user. Args: current_user: Current authenticated user db: Database session limit: Maximum number of boards to return offset: Number of boards to skip Returns: Dictionary with boards list, total count, limit, and offset """ repo = BoardRepository(db) boards, total = repo.get_user_boards(user_id=current_user.id, limit=limit, offset=offset) return { "boards": [BoardSummary.model_validate(board) for board in boards], "total": total, "limit": limit, "offset": offset, } @router.get("/{board_id}", response_model=BoardDetail) def get_board( board_id: UUID, current_user: Annotated[User, Depends(get_current_user)], db: Annotated[Session, Depends(get_db_sync)], ): """ Get board details by ID. Args: board_id: Board UUID current_user: Current authenticated user db: Database session Returns: Board details Raises: HTTPException: 404 if board not found or not owned by user """ repo = BoardRepository(db) board = repo.get_board_by_id(board_id=board_id, user_id=current_user.id) if not board: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Board {board_id} not found", ) return BoardDetail.model_validate(board) @router.patch("/{board_id}", response_model=BoardDetail) def update_board( board_id: UUID, board_data: BoardUpdate, current_user: Annotated[User, Depends(get_current_user)], db: Annotated[Session, Depends(get_db_sync)], ): """ Update board metadata. Args: board_id: Board UUID board_data: Board update data current_user: Current authenticated user db: Database session Returns: Updated board details Raises: HTTPException: 404 if board not found or not owned by user """ repo = BoardRepository(db) # Convert viewport_state to dict if provided viewport_dict = None if board_data.viewport_state: viewport_dict = board_data.viewport_state.model_dump() board = repo.update_board( board_id=board_id, user_id=current_user.id, title=board_data.title, description=board_data.description, viewport_state=viewport_dict, ) if not board: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Board {board_id} not found", ) return BoardDetail.model_validate(board) @router.patch("/{board_id}/viewport", status_code=status.HTTP_204_NO_CONTENT) def update_viewport( board_id: UUID, viewport_data: ViewportStateUpdate, current_user: Annotated[User, Depends(get_current_user)], db: Annotated[Session, Depends(get_db_sync)], ): """ Update board viewport state only (optimized for frequent updates). This endpoint is designed for high-frequency viewport state updates (debounced pan/zoom/rotate changes) with minimal overhead. Args: board_id: Board UUID viewport_data: Viewport state data current_user: Current authenticated user db: Database session Raises: HTTPException: 404 if board not found or not owned by user """ repo = BoardRepository(db) # Convert viewport data to dict viewport_dict = viewport_data.model_dump() board = repo.update_board( board_id=board_id, user_id=current_user.id, title=None, description=None, viewport_state=viewport_dict, ) if not board: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Board {board_id} not found", ) @router.delete("/{board_id}", status_code=status.HTTP_204_NO_CONTENT) def delete_board( board_id: UUID, current_user: Annotated[User, Depends(get_current_user)], db: Annotated[Session, Depends(get_db_sync)], ): """ Delete a board (soft delete). Args: board_id: Board UUID current_user: Current authenticated user db: Database session Raises: HTTPException: 404 if board not found or not owned by user """ repo = BoardRepository(db) success = repo.delete_board(board_id=board_id, user_id=current_user.id) if not success: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Board {board_id} not found", )