from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy import select from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import Session from app.api.deps import require_admin_session from app.db.session import get_db from app.models.client_access import ClientAccount, ClientFeatureAccess, ClientUser from app.schemas.client_access import ClientAccessRead, ClientFeatureUpdate, ClientUserCreate, ClientUserUpdate from app.services.client_access_service import list_client_accounts, serialize_client_account router = APIRouter(prefix="/api/client-access", tags=["client-access"]) def _get_client_or_404(db: Session, client_id: int) -> ClientAccount: client = db.scalar(select(ClientAccount).where(ClientAccount.id == client_id)) if client is None: raise HTTPException(status_code=404, detail="Client account not found") return client def _read_client_account(db: Session, client_id: int) -> dict: client = next((item for item in list_client_accounts(db) if item.id == client_id), None) if client is None: raise HTTPException(status_code=404, detail="Client account not found") return serialize_client_account(client) @router.get("", response_model=list[ClientAccessRead]) def get_client_access(db: Session = Depends(get_db), _: object = Depends(require_admin_session)): return [serialize_client_account(client) for client in list_client_accounts(db)] @router.post("/users", response_model=ClientAccessRead, status_code=status.HTTP_201_CREATED) def create_client_user( payload: ClientUserCreate, db: Session = Depends(get_db), _: object = Depends(require_admin_session), ): client = _get_client_or_404(db, payload.client_account_id) user = ClientUser(tenant_id=client.tenant_id, **payload.model_dump()) db.add(user) try: db.commit() except IntegrityError as exc: db.rollback() raise HTTPException(status_code=409, detail="A user with that email already exists for this client") from exc return _read_client_account(db, payload.client_account_id) @router.patch("/users/{user_id}", response_model=ClientAccessRead) def update_client_user(user_id: int, payload: ClientUserUpdate, db: Session = Depends(get_db), _: object = Depends(require_admin_session)): user = db.scalar(select(ClientUser).where(ClientUser.id == user_id)) if user is None: raise HTTPException(status_code=404, detail="Client user not found") for field, value in payload.model_dump(exclude_unset=True).items(): setattr(user, field, value) try: db.commit() except IntegrityError as exc: db.rollback() raise HTTPException(status_code=409, detail="A user with that email already exists for this client") from exc return _read_client_account(db, user.client_account_id) @router.patch("/features/{feature_id}", response_model=ClientAccessRead) def update_client_feature( feature_id: int, payload: ClientFeatureUpdate, db: Session = Depends(get_db), _: object = Depends(require_admin_session), ): feature = db.scalar(select(ClientFeatureAccess).where(ClientFeatureAccess.id == feature_id)) if feature is None: raise HTTPException(status_code=404, detail="Client feature not found") feature.enabled = payload.enabled db.commit() return _read_client_account(db, feature.client_account_id)