from __future__ import annotations from datetime import datetime from typing import Annotated from fastapi import APIRouter, Depends, Query from core.auth.models import CurrentUser from core.http.errors import ApiProblemError, problem_payload from v1.points.dependencies import get_points_service from v1.points.schemas import ( PackagesResponse, PackageInfo, PointsBalanceResponse, LedgerListResponse, LedgerItem, ) from v1.points.service import PointsService from v1.users.dependencies import get_current_user router = APIRouter(prefix="/points", tags=["points"]) def _parse_cursor(cursor: str | None) -> datetime | None: if cursor is None: return None try: return datetime.fromisoformat(cursor.replace("Z", "+00:00")) except ValueError as exc: raise ApiProblemError( status_code=422, detail=problem_payload( code="POINTS_INVALID_CURSOR", detail="Points ledger cursor must be an ISO 8601 datetime", params={"cursor": cursor}, ), ) from exc @router.get("/balance", response_model=PointsBalanceResponse) async def get_points_balance( service: Annotated[PointsService, Depends(get_points_service)], current_user: Annotated[CurrentUser, Depends(get_current_user)], ) -> PointsBalanceResponse: result = await service.get_points_balance(user_id=current_user.id) return PointsBalanceResponse( balance=result.balance, frozenBalance=result.frozen_balance, availableBalance=result.available_balance, runCost=result.run_cost, canRun=result.can_run, ) @router.get("/packages", response_model=PackagesResponse) async def get_available_packages( service: Annotated[PointsService, Depends(get_points_service)], current_user: Annotated[CurrentUser, Depends(get_current_user)], ) -> PackagesResponse: result = await service.get_available_packages( user_id=current_user.id, user_email=current_user.email or "", ) return PackagesResponse( packages=[ PackageInfo( productCode=pkg.product_code, appStoreProductId=pkg.app_store_product_id, type=pkg.type, credits=pkg.credits, isStarter=pkg.is_starter, starterEligible=pkg.starter_eligible, sortOrder=pkg.sort_order, ) for pkg in result.packages ], ) @router.get("/ledger", response_model=LedgerListResponse) async def get_points_ledger( service: Annotated[PointsService, Depends(get_points_service)], current_user: Annotated[CurrentUser, Depends(get_current_user)], limit: Annotated[int, Query(ge=1, le=100)] = 20, cursor: str | None = None, ) -> LedgerListResponse: items, next_cursor, has_more = await service.get_ledger_list( user_id=current_user.id, limit=limit, cursor=_parse_cursor(cursor), ) return LedgerListResponse( items=[ LedgerItem( id=item.id, direction=item.direction, amount=item.amount, balanceAfter=item.balance_after, changeType=item.change_type, createdAt=item.created_at, ) for item in items ], nextCursor=next_cursor, hasMore=has_more, )