"""Strategy set service orchestration.""" from __future__ import annotations from fastapi import Depends from app.core.config import Settings, get_settings from app.domain.models import StrategySet from app.repositories.factory import get_portfolio_repository_from_settings from app.repositories.portfolio_repository import PortfolioRepository from app.schemas.portfolio import CreateStrategySetRequest, UpdateStrategySetRequest def get_strategy_set_repository(settings: Settings = Depends(get_settings)) -> PortfolioRepository: return get_portfolio_repository_from_settings(settings) class StrategySetService: def __init__(self, repository: PortfolioRepository) -> None: self._repository = repository def list(self) -> list[StrategySet]: """List all strategy sets.""" return self._repository.list_strategy_sets() def get(self, strategy_set_id: str) -> StrategySet | None: """Get a single strategy set by ID.""" return self._repository.get_strategy_set(strategy_set_id) def create(self, payload: CreateStrategySetRequest) -> StrategySet: """Create or get existing strategy set. Uses get_or_create_strategy_set for idempotence. """ return self._repository.get_or_create_strategy_set(payload.name, payload.config) def update(self, strategy_set_id: str, payload: UpdateStrategySetRequest) -> StrategySet: """Update a strategy set. Since strategy sets are identified by (name, config) uniqueness, updating requires creating a new one if name/config changes. """ current = self.get(strategy_set_id) if current is None: raise ValueError(f"Strategy set {strategy_set_id} not found") # Use provided values or fall back to current ones new_name = payload.name if payload.name is not None else current.name new_config = payload.config if payload.config is not None else current.config # If nothing changed, return current if new_name == current.name and new_config == current.config: return current # Create or get the new strategy set new_strategy_set = self._repository.get_or_create_strategy_set(new_name, new_config) # If the new strategy set is different from current, delete the old one # (only if it's not in use - delete_strategy_set will raise if in use) if new_strategy_set.id != strategy_set_id: try: self._repository.delete_strategy_set(strategy_set_id) except ValueError: # If old strategy set is in use, keep it and return new one pass return new_strategy_set def delete(self, strategy_set_id: str) -> None: """Delete a strategy set. Raises ValueError if the strategy set is in use by any portfolio. """ self._repository.delete_strategy_set(strategy_set_id)