"""Contact 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.user import User from app.schemas.contact import ContactCreate, ContactOut, ContactUpdate from app.services.contact_service import ( InvalidAccount, create_contact as svc_create_contact, get_contact as svc_get_contact, list_contacts as svc_list_contacts, soft_delete_contact as svc_soft_delete_contact, update_contact as svc_update_contact, ) router = APIRouter(prefix="/contacts", tags=["contacts"]) @router.post( "/", response_model=ContactOut, status_code=status.HTTP_201_CREATED, summary="Create a new contact", ) async def create_contact( payload: ContactCreate, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ) -> ContactOut: try: contact = await svc_create_contact( db, payload, org_id=current_user.org_id, owner_id=current_user.id ) except InvalidAccount as e: raise HTTPException(status_code=404, detail=str(e)) from e return ContactOut.model_validate(contact) @router.get( "/", response_model=list[ContactOut], summary="List contacts (paginated, filterable)", ) async def list_contacts( skip: int = Query(0, ge=0), limit: int = Query(20, ge=1, le=100), account_id: Optional[int] = None, owner_id: Optional[int] = None, q: Optional[str] = None, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ) -> list[ContactOut]: contacts = await svc_list_contacts( db, org_id=current_user.org_id, skip=skip, limit=limit, account_id=account_id, owner_id=owner_id, q=q, ) return [ContactOut.model_validate(c) for c in contacts] @router.get( "/{contact_id}", response_model=ContactOut, summary="Get one contact", ) async def get_contact( contact_id: int, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ) -> ContactOut: contact = await svc_get_contact(db, contact_id, org_id=current_user.org_id) if contact is None: raise HTTPException(status_code=404, detail="Contact not found") return ContactOut.model_validate(contact) @router.patch( "/{contact_id}", response_model=ContactOut, summary="Update a contact", ) async def update_contact( contact_id: int, payload: ContactUpdate, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ) -> ContactOut: contact = await svc_get_contact(db, contact_id, org_id=current_user.org_id) if contact is None: raise HTTPException(status_code=404, detail="Contact not found") try: updated = await svc_update_contact(db, contact, payload) except InvalidAccount as e: raise HTTPException(status_code=404, detail=str(e)) from e return ContactOut.model_validate(updated) @router.delete( "/{contact_id}", status_code=status.HTTP_204_NO_CONTENT, response_class=Response, summary="Soft-delete a contact", ) async def delete_contact( contact_id: int, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ) -> Response: contact = await svc_get_contact(db, contact_id, org_id=current_user.org_id) if contact is None: raise HTTPException(status_code=404, detail="Contact not found") await svc_soft_delete_contact(db, contact) return Response(status_code=status.HTTP_204_NO_CONTENT) __all__ = ["router"]