"""Activity API endpoints.""" from __future__ import annotations from typing import Optional from fastapi import APIRouter, Depends, HTTPException, Query, Response, status from sqlalchemy.ext.asyncio import AsyncSession from app.core.db import get_db from app.core.deps import get_current_user from app.models.activity import ActivityType from app.models.user import User from app.schemas.activity import ( ActivityCompleteRequest, ActivityCreate, ActivityOut, ActivityUpdate, ) from app.services.activity_service import ( NoParentException, complete_activity as svc_complete_activity, create_activity as svc_create_activity, get_activity as svc_get_activity, list_activities as svc_list_activities, soft_delete_activity as svc_soft_delete_activity, update_activity as svc_update_activity, ) router = APIRouter(prefix="/activities", tags=["activities"]) @router.post( "/", response_model=ActivityOut, status_code=status.HTTP_201_CREATED, summary="Create a new activity (polymorphic parent: account/contact/deal)", ) async def create_activity( payload: ActivityCreate, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ) -> ActivityOut: try: activity = await svc_create_activity( db, payload, org_id=current_user.org_id, owner_id=current_user.id ) except NoParentException as e: raise HTTPException(status_code=422, detail=str(e)) from e return ActivityOut.model_validate(activity) @router.get( "/", response_model=list[ActivityOut], summary="List activities (paginated, filterable)", ) async def list_activities( skip: int = Query(0, ge=0), limit: int = Query(20, ge=1, le=100), type: Optional[ActivityType] = None, owner_id: Optional[int] = None, overdue: Optional[bool] = None, completed: Optional[bool] = None, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ) -> list[ActivityOut]: activities = await svc_list_activities( db, org_id=current_user.org_id, skip=skip, limit=limit, type=type, owner_id=owner_id, overdue=overdue, completed=completed, ) return [ActivityOut.model_validate(a) for a in activities] @router.get( "/{activity_id}", response_model=ActivityOut, summary="Get one activity", ) async def get_activity( activity_id: int, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ) -> ActivityOut: activity = await svc_get_activity( db, activity_id, org_id=current_user.org_id ) if activity is None: raise HTTPException(status_code=404, detail="Activity not found") return ActivityOut.model_validate(activity) @router.patch( "/{activity_id}", response_model=ActivityOut, summary="Update an activity", ) async def update_activity( activity_id: int, payload: ActivityUpdate, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ) -> ActivityOut: activity = await svc_get_activity( db, activity_id, org_id=current_user.org_id ) if activity is None: raise HTTPException(status_code=404, detail="Activity not found") try: updated = await svc_update_activity(db, activity, payload) except NoParentException as e: raise HTTPException(status_code=422, detail=str(e)) from e return ActivityOut.model_validate(updated) @router.patch( "/{activity_id}/complete", response_model=ActivityOut, summary="Mark an activity as completed", ) async def complete_activity( activity_id: int, payload: ActivityCompleteRequest, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ) -> ActivityOut: activity = await svc_get_activity( db, activity_id, org_id=current_user.org_id ) if activity is None: raise HTTPException(status_code=404, detail="Activity not found") updated = await svc_complete_activity(db, activity, payload) return ActivityOut.model_validate(updated) @router.delete( "/{activity_id}", status_code=status.HTTP_204_NO_CONTENT, response_class=Response, summary="Soft-delete an activity", ) async def delete_activity( activity_id: int, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ) -> Response: activity = await svc_get_activity( db, activity_id, org_id=current_user.org_id ) if activity is None: raise HTTPException(status_code=404, detail="Activity not found") await svc_soft_delete_activity(db, activity) return Response(status_code=status.HTTP_204_NO_CONTENT) __all__ = ["router"]