"""Environment helpers for Alibaba Cloud billing.""" from __future__ import annotations from dataclasses import dataclass, field from pathlib import Path from typing import Dict, Iterable, List, Optional, Set @dataclass class Environment: """Container for a single environment's configuration.""" name: str display_name: str accounts: Set[str] = field(default_factory=set) webhook_url: Optional[str] = None class EnvironmentManager: """Resolve account→environment mappings and ensure export directories exist.""" def __init__( self, environments_config: Optional[Dict[str, Dict]] = None, output_dir: Optional[Path] = None, default_environment: str = "unassigned", cloud_webhook_url: Optional[str] = None, ) -> None: self.default_environment = default_environment self.output_dir = output_dir self.cloud_webhook_url = cloud_webhook_url self._environments: Dict[str, Environment] = {} if environments_config: self._load_environments(environments_config) if self.output_dir: self._ensure_directories() def _load_environments(self, environments_config: Dict[str, Dict]) -> None: for env_key, raw in environments_config.items(): accounts: Iterable[str] = raw.get("accounts", []) or [] normalized_accounts = {str(account).strip() for account in accounts if str(account).strip()} env = Environment( name=env_key, display_name=str(raw.get("name") or env_key), accounts=normalized_accounts, webhook_url=raw.get("webhook_url") or raw.get("webhookUrl"), ) self._environments[env_key] = env # Always ensure the default placeholder environment exists. if self.default_environment not in self._environments: self._environments[self.default_environment] = Environment( name=self.default_environment, display_name=self.default_environment.capitalize(), accounts=set(), webhook_url=None, ) def _ensure_directories(self) -> None: if not self.output_dir: return for env_name in self._environments: env_dir = self.output_dir / env_name env_dir.mkdir(parents=True, exist_ok=True) def list_environments(self) -> List[str]: return list(self._environments.keys()) def get_environment(self, env_name: str) -> Optional[Environment]: return self._environments.get(env_name) def accounts_for_environment(self, env_name: str) -> Set[str]: env = self.get_environment(env_name) return env.accounts if env else set() def resolve_environment_for_account(self, account_id: str) -> str: account_id = str(account_id).strip() if not account_id: return self.default_environment for env in self._environments.values(): if account_id in env.accounts: return env.name return self.default_environment def webhook_for_environment(self, env_name: str) -> Optional[str]: env = self.get_environment(env_name) if env and env.webhook_url: return env.webhook_url return self.cloud_webhook_url def display_name_for_environment(self, env_name: str) -> str: env = self.get_environment(env_name) if env: return env.display_name return env_name