"""Strategy Set API routes.""" from fastapi import APIRouter, Depends, Response, status from app.core.auth import AuthContext, require_read, require_trade_write from app.core.config import Settings, get_settings from app.repositories.factory import get_portfolio_repository_from_settings from app.schemas.portfolio import CreateStrategySetRequest, StrategySetResponse, UpdateStrategySetRequest from app.services.strategy_set_service import StrategySetService router = APIRouter(prefix="/strategy-sets", tags=["strategy-sets"]) def _get_service(settings: Settings) -> tuple[StrategySetService, object]: repository = get_portfolio_repository_from_settings(settings) return StrategySetService(repository), repository def _close_repository(repository: object) -> None: if callable(getattr(type(repository), "close", None)): repository.close() @router.get("", response_model=list[StrategySetResponse]) def list_strategy_sets( _auth: AuthContext = Depends(require_read), settings: Settings = Depends(get_settings), ) -> list[StrategySetResponse]: """List all strategy sets.""" service, repository = _get_service(settings) try: strategy_sets = service.list() finally: _close_repository(repository) return [ StrategySetResponse( id=ss.id, name=ss.name, config=ss.config, nick=ss.nick, created_at=ss.created_at, ) for ss in strategy_sets ] @router.post("", response_model=StrategySetResponse, status_code=status.HTTP_201_CREATED) def create_strategy_set( payload: CreateStrategySetRequest, _auth: AuthContext = Depends(require_trade_write), settings: Settings = Depends(get_settings), ) -> StrategySetResponse: """Create a new strategy set (or return existing if (name, config) pair already exists).""" service, repository = _get_service(settings) try: strategy_set = service.create(payload) finally: _close_repository(repository) return StrategySetResponse( id=strategy_set.id, name=strategy_set.name, config=strategy_set.config, nick=strategy_set.nick, created_at=strategy_set.created_at, ) @router.patch("/{strategy_set_id}", response_model=StrategySetResponse) def update_strategy_set( strategy_set_id: str, payload: UpdateStrategySetRequest, _auth: AuthContext = Depends(require_trade_write), settings: Settings = Depends(get_settings), ) -> StrategySetResponse: """Update a strategy set's name and/or config. Note: Since strategy sets are identified by (name, config) uniqueness, updating may result in a new strategy set ID if name or config changes. """ service, repository = _get_service(settings) try: strategy_set = service.update(strategy_set_id, payload) finally: _close_repository(repository) return StrategySetResponse( id=strategy_set.id, name=strategy_set.name, config=strategy_set.config, nick=strategy_set.nick, created_at=strategy_set.created_at, ) @router.delete("/{strategy_set_id}", status_code=status.HTTP_204_NO_CONTENT) def delete_strategy_set( strategy_set_id: str, _auth: AuthContext = Depends(require_trade_write), settings: Settings = Depends(get_settings), ) -> Response: """Delete a strategy set. Returns 204 No Content on success. Returns 409 Conflict if the strategy set is in use by any portfolio. """ try: service, repository = _get_service(settings) try: service.delete(strategy_set_id) finally: _close_repository(repository) except ValueError as e: # If strategy set is in use, return 409 Conflict raise ValueError(str(e)) from e return Response(status_code=status.HTTP_204_NO_CONTENT)