"""Composition root + общие хелперы для CLI-команд.""" from __future__ import annotations from decimal import Decimal from rich.console import Console from application.forecast import ForecastService from application.scenarios import ScenarioService from domain import CurrencyConverter, FinancialModel from infrastructure.ai.assistant import AssistantService from infrastructure.cli.paths import MODEL_PATH from infrastructure.repositories import JsonFileRepository console = Console() _json_repo = JsonFileRepository() def load_model() -> FinancialModel: if MODEL_PATH.exists(): return _json_repo.load(MODEL_PATH) return FinancialModel() def save_model(model: FinancialModel) -> None: _json_repo.save(model, MODEL_PATH) def build_services(model: FinancialModel) -> tuple[ForecastService, ScenarioService, AssistantService, CurrencyConverter]: """Composition root: собрать граф сервисов с зависимостями.""" converter = CurrencyConverter(model.exchange_rates) forecast_service = ForecastService(model) scenario_service = ScenarioService(model) assistant_service = AssistantService( model, forecast_service=forecast_service, converter=converter ) return forecast_service, scenario_service, assistant_service, converter def resolve_currency(model: FinancialModel, currency: str | None) -> tuple[str, str]: target = currency or model.base_currency converter = CurrencyConverter(model.exchange_rates) symbol = converter.get_symbol(target) return target, symbol def convert_value( converter: CurrencyConverter, amount: Decimal, from_curr: str, to_curr: str ) -> Decimal: if to_curr == from_curr: return amount return converter.convert(amount, from_curr, to_curr) def fmt_amount(amount: Decimal | float, currency: str, symbol: str) -> str: if isinstance(amount, Decimal): return f"{symbol}{amount:,.2f}" return f"{symbol}{amount:,.2f}"