"""GET /api/customers — paginated, filterable customer list. Read-only query over the mirrored ``customer`` table. Supports filtering by ``channel``, ``owner_account_id``, ``user_id``, ``add_time_since`` and ``last_chat_since`` (direct columns) and ``department_id`` (resolved through ``customer.user_id`` -> ``staff.dept_id``). Results are ordered by ``last_chat_time desc`` (nulls last) then ``friend_id`` so the most-recently-active contacts surface first. """ from __future__ import annotations from typing import Annotated import sqlalchemy as sa from fastapi import APIRouter, Depends, Query from sqlalchemy.ext.asyncio import AsyncSession from app.api.deps import get_session from app.api.schemas import CustomerOut, Page from app.db.models import Customer, Staff router = APIRouter(prefix="/api", tags=["customers"]) SessionDep = Annotated[AsyncSession, Depends(get_session)] PageParam = Annotated[int, Query(ge=1)] PageSizeParam = Annotated[int, Query(ge=1, le=100)] @router.get("/customers") async def list_customers( session: SessionDep, page: PageParam = 1, page_size: PageSizeParam = 20, channel: Annotated[str | None, Query()] = None, department_id: Annotated[str | None, Query()] = None, owner_account_id: Annotated[str | None, Query()] = None, user_id: Annotated[str | None, Query()] = None, add_time_since: Annotated[int | None, Query(ge=0)] = None, last_chat_since: Annotated[int | None, Query(ge=0)] = None, ) -> Page[CustomerOut]: """List customers with optional filters and pagination.""" conditions = [] if channel is not None: conditions.append(Customer.channel == channel) if owner_account_id is not None: conditions.append(Customer.owner_account_id == owner_account_id) if department_id is not None: # Customer has no dept column; resolve via the owning staff member. dept_user_ids = sa.select(Staff.user_id).where( Staff.dept_id == department_id ) conditions.append(Customer.user_id.in_(dept_user_ids)) if user_id is not None: conditions.append(Customer.user_id == user_id) if add_time_since is not None: conditions.append(Customer.add_time >= add_time_since) if last_chat_since is not None: conditions.append(Customer.last_chat_time >= last_chat_since) total_stmt = sa.select(sa.func.count()).select_from(Customer) if conditions: total_stmt = total_stmt.where(*conditions) total = (await session.execute(total_stmt)).scalar_one() list_stmt = sa.select(Customer) if conditions: list_stmt = list_stmt.where(*conditions) list_stmt = ( list_stmt.order_by( sa.nullslast(Customer.last_chat_time.desc()), Customer.friend_id.asc(), ) .limit(page_size) .offset((page - 1) * page_size) ) rows = (await session.execute(list_stmt)).scalars().all() items = [CustomerOut.model_validate(row) for row in rows] return Page(items=items, total=total, page=page, page_size=page_size)