""" ProjectState API router for ClaudeTools. Defines all REST API endpoints for managing project states, tracking the current state of projects for context retrieval. """ from uuid import UUID from fastapi import APIRouter, Depends, HTTPException, Query, status from sqlalchemy.orm import Session from api.database import get_db from api.middleware.auth import get_current_user from api.schemas.project_state import ( ProjectStateCreate, ProjectStateResponse, ProjectStateUpdate, ) from api.services import project_state_service # Create router with prefix and tags router = APIRouter() @router.get( "", response_model=dict, summary="List all project states", description="Retrieve a paginated list of all project states", status_code=status.HTTP_200_OK, ) def list_project_states( skip: int = Query( default=0, ge=0, description="Number of records to skip for pagination" ), limit: int = Query( default=100, ge=1, le=1000, description="Maximum number of records to return (max 1000)" ), db: Session = Depends(get_db), current_user: dict = Depends(get_current_user), ): """ List all project states with pagination. Returns project states ordered by most recently updated. """ try: states, total = project_state_service.get_project_states(db, skip, limit) return { "total": total, "skip": skip, "limit": limit, "states": [ProjectStateResponse.model_validate(state) for state in states] } except Exception as e: raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Failed to retrieve project states: {str(e)}" ) @router.get( "/by-project/{project_id}", response_model=ProjectStateResponse, summary="Get project state by project ID", description="Retrieve the project state for a specific project (unique per project)", status_code=status.HTTP_200_OK, ) def get_project_state_by_project( project_id: UUID, db: Session = Depends(get_db), current_user: dict = Depends(get_current_user), ): """ Get the project state for a specific project. Each project has exactly one project state. """ state = project_state_service.get_project_state_by_project(db, project_id) if not state: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"ProjectState for project ID {project_id} not found" ) return ProjectStateResponse.model_validate(state) @router.get( "/{state_id}", response_model=ProjectStateResponse, summary="Get project state by ID", description="Retrieve a single project state by its unique identifier", status_code=status.HTTP_200_OK, ) def get_project_state( state_id: UUID, db: Session = Depends(get_db), current_user: dict = Depends(get_current_user), ): """ Get a specific project state by ID. """ state = project_state_service.get_project_state_by_id(db, state_id) return ProjectStateResponse.model_validate(state) @router.post( "", response_model=ProjectStateResponse, summary="Create new project state", description="Create a new project state with the provided details", status_code=status.HTTP_201_CREATED, ) def create_project_state( state_data: ProjectStateCreate, db: Session = Depends(get_db), current_user: dict = Depends(get_current_user), ): """ Create a new project state. Each project can only have one project state (enforced by unique constraint). Requires a valid JWT token with appropriate permissions. """ state = project_state_service.create_project_state(db, state_data) return ProjectStateResponse.model_validate(state) @router.put( "/{state_id}", response_model=ProjectStateResponse, summary="Update project state", description="Update an existing project state's details", status_code=status.HTTP_200_OK, ) def update_project_state( state_id: UUID, state_data: ProjectStateUpdate, db: Session = Depends(get_db), current_user: dict = Depends(get_current_user), ): """ Update an existing project state. Only provided fields will be updated. All fields are optional. Uses compression utilities when updating to maintain efficient storage. """ state = project_state_service.update_project_state(db, state_id, state_data) return ProjectStateResponse.model_validate(state) @router.put( "/by-project/{project_id}", response_model=ProjectStateResponse, summary="Update project state by project ID", description="Update project state by project ID (creates if doesn't exist)", status_code=status.HTTP_200_OK, ) def update_project_state_by_project( project_id: UUID, state_data: ProjectStateUpdate, db: Session = Depends(get_db), current_user: dict = Depends(get_current_user), ): """ Update project state by project ID. Convenience method that creates a new project state if it doesn't exist, or updates the existing one if it does. """ state = project_state_service.update_project_state_by_project(db, project_id, state_data) return ProjectStateResponse.model_validate(state) @router.delete( "/{state_id}", response_model=dict, summary="Delete project state", description="Delete a project state by its ID", status_code=status.HTTP_200_OK, ) def delete_project_state( state_id: UUID, db: Session = Depends(get_db), current_user: dict = Depends(get_current_user), ): """ Delete a project state. This is a permanent operation and cannot be undone. """ return project_state_service.delete_project_state(db, state_id)