import logging from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy.ext.asyncio import AsyncSession from app.database import get_transactional_session from app.auth import current_active_user from app.models import User as UserModel, Expense as ExpenseModel from app.schemas.cost import ListCostSummary, GroupBalanceSummary from app.schemas.expense import ExpensePublic from app.services import costs_service from app.core.exceptions import ( ListNotFoundError, ListPermissionError, GroupNotFoundError, GroupPermissionError, InvalidOperationError ) logger = logging.getLogger(__name__) router = APIRouter() @router.get( "/lists/{list_id}/cost-summary", response_model=ListCostSummary, summary="Get Cost Summary for a List", tags=["Costs"], responses={ status.HTTP_403_FORBIDDEN: {"description": "User does not have permission to access this list"}, status.HTTP_404_NOT_FOUND: {"description": "List not found"}, }, ) async def get_list_cost_summary( list_id: int, db: AsyncSession = Depends(get_transactional_session), current_user: UserModel = Depends(current_active_user), ): """ Retrieves a calculated cost summary for a specific list. If an expense has been generated for this list, the summary will be based on that. Otherwise, it will be a basic summary of item prices. This endpoint is idempotent and does not create any data. """ logger.info(f"User {current_user.email} requesting cost summary for list {list_id}") try: return await costs_service.get_list_cost_summary_logic( db=db, list_id=list_id, current_user_id=current_user.id ) except ListPermissionError as e: logger.warning(f"Permission denied for user {current_user.email} on list {list_id}: {str(e)}") raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=str(e)) except ListNotFoundError as e: logger.warning(f"List {list_id} not found when getting cost summary: {str(e)}") raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(e)) @router.post( "/lists/{list_id}/cost-summary", response_model=ExpensePublic, status_code=status.HTTP_201_CREATED, summary="Generate and Get Expense from List Summary", tags=["Costs"], responses={ status.HTTP_403_FORBIDDEN: {"description": "User does not have permission to access this list"}, status.HTTP_404_NOT_FOUND: {"description": "List not found"}, status.HTTP_400_BAD_REQUEST: {"description": "Invalid operation (e.g., no items to expense, or expense already exists)"}, }, ) async def generate_expense_from_list_summary( list_id: int, db: AsyncSession = Depends(get_transactional_session), current_user: UserModel = Depends(current_active_user), ): """ Creates an ITEM_BASED expense from the items in a given list. This should be called to finalize the costs for a shopping list and turn it into a formal expense. It will fail if an expense for this list already exists. """ logger.info(f"User {current_user.email} requesting to generate expense from list {list_id}") try: expense = await costs_service.generate_expense_from_list_logic( db=db, list_id=list_id, current_user_id=current_user.id ) return expense except (ListPermissionError, GroupPermissionError) as e: logger.warning(f"Permission denied for user {current_user.email} on list {list_id}: {str(e)}") raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=str(e)) except (ListNotFoundError, GroupNotFoundError) as e: logger.warning(f"Resource not found for list {list_id}: {str(e)}") raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(e)) except InvalidOperationError as e: logger.warning(f"Invalid operation for list {list_id}: {str(e)}") raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e)) @router.get( "/groups/{group_id}/balance-summary", response_model=GroupBalanceSummary, summary="Get Detailed Balance Summary for a Group", tags=["Costs", "Groups"], responses={ status.HTTP_403_FORBIDDEN: {"description": "User does not have permission to access this group"}, status.HTTP_404_NOT_FOUND: {"description": "Group not found"}, }, ) async def get_group_balance_summary( group_id: int, db: AsyncSession = Depends(get_transactional_session), current_user: UserModel = Depends(current_active_user), ): """ Retrieves a detailed financial balance summary for all users within a specific group. It considers all expenses, their splits, and all settlements recorded for the group. The user must be a member of the group to view its balance summary. """ logger.info(f"User {current_user.email} requesting balance summary for group {group_id}") try: return await costs_service.get_group_balance_summary_logic( db=db, group_id=group_id, current_user_id=current_user.id ) except GroupPermissionError as e: logger.warning(f"Permission denied for user {current_user.email} on group {group_id}: {str(e)}") raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=str(e)) except GroupNotFoundError as e: logger.warning(f"Group {group_id} not found when getting balance summary: {str(e)}") raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(e))