  # #region profile_service [C:5] [TYPE Module] [SEMANTICS sqlalchemy, profile, preference, superset, lookup]
  # @defgroup Services Module group.
  #
  # @BRIEF Composite facade orchestrating profile preference persistence, Superset account lookup,
  #        security badges, and deterministic actor matching by delegating to focused sub-services.
  # @LAYER     Domain
  # @RELATION DEPENDS_ON -> [UserDashboardPreference]
  # @RELATION DEPENDS_ON -> [ProfilePreferenceResponse]
  # @RELATION DEPENDS_ON -> [SupersetClient]
  # @RELATION DEPENDS_ON -> [AuthRepositoryModule]
  # @RELATION DEPENDS_ON -> [User]
  # @RELATION DEPENDS_ON -> [EXT:Library:sqlalchemy.orm.Session]
  # @RELATION DEPENDS_ON -> [ProfilePreferenceService]
  # @RELATION DEPENDS_ON -> [SupersetLookupService]
  # @RELATION DEPENDS_ON -> [SecurityBadgeService]
  # @RELATION DEPENDS_ON -> [ProfileUtils]
  #
  # @INVARIANT  Profile ID needs to be unique per-user session
  #
  # @TEST_CONTRACT  ProfilePreferenceUpdateRequest -> ProfilePreferenceResponse
  # @TEST_FIXTURE  valid_profile_update -> {"user_id":"u-1","superset_username":"John_Doe","show_only_my_dashboards":true}
  # @TEST_EDGE  enable_without_username -> toggle=true with empty username returns validation error
  # @TEST_EDGE  cross_user_mutation -> attempt to update another user preference returns forbidden
  # @TEST_EDGE  lookup_env_not_found -> unknown environment_id returns not found
  # @TEST_INVARIANT  normalization_consistency -> VERIFIED_BY: [valid_profile_update, enable_without_username]
  # @DATA_CONTRACT  Profile_id -> ProfileInfo; session_id -> valid UUID
  # @PRE  Session is active and valid
  # @POST  Profile with updated fields populated and
  # @SIDE_EFFECT  Database read/write operations
  # @RATIONALE Decomposed from monolithic 770-line ProfileService into three focused services
  #            (ProfilePreferenceService, SupersetLookupService, SecurityBadgeService) plus pure
  #            utility functions (ProfileUtils) to satisfy INV_7. This module is a thin facade
  #            that preserves the public API contract for all existing callers.
  # @REJECTED Keeping all three domains in a single ProfileService class was rejected — it violated
  #            INV_7 (770 lines vs 150 max), mixed I/O patterns (DB writes + HTTP calls), and created
  #            unnecessary coupling between preference persistence and Superset network operations.
  
> from collections.abc import Iterable
> from typing import Any
  
> from sqlalchemy.orm import Session
  
> from ..models.auth import User
> from ..schemas.profile import (
>     ProfilePreferenceResponse,
>     ProfilePreferenceUpdateRequest,
>     SupersetAccountLookupRequest,
>     SupersetAccountLookupResponse,
> )
> from .profile_preference_service import ProfilePreferenceService
> from .profile_utils import (
>     EnvironmentNotFoundError,
>     ProfileAuthorizationError,
>     ProfileValidationError,
>     normalize_owner_tokens,
>     normalize_username,
> )
> from .security_badge_service import SecurityBadgeService
> from .superset_lookup_service import SupersetLookupService
  
  # Re-export exception classes for backward-compatible imports
> __all__ = [
>     "EnvironmentNotFoundError",
>     "ProfileAuthorizationError",
>     "ProfilePreferenceService",
>     "ProfileService",
>     "ProfileValidationError",
>     "SecurityBadgeService",
>     "SupersetLookupService",
> ]
  
  
  # #region ProfileService [C:4] [TYPE Class] [SEMANTICS profile,facade,delegate,coordinator]
  # @defgroup Services Module group.
  # @BRIEF Facade that composes ProfilePreferenceService, SupersetLookupService, and
  #        SecurityBadgeService into a single interface for backward compatibility.
  # @RELATION DEPENDS_ON -> [ProfilePreferenceService]
  # @RELATION DEPENDS_ON -> [SupersetLookupService]
  # @RELATION DEPENDS_ON -> [SecurityBadgeService]
  # @RELATION DEPENDS_ON -> [ProfileUtils]
  # @PRE  Caller provides authenticated User context for external service methods.
  # @POST  Delegates to sub-services and returns normalized profile/lookup responses.
  # @SIDE_EFFECT  Writes preference records and encrypted tokens; performs external account lookups when requested.
  # @DATA_CONTRACT  Input[User,ProfilePreferenceUpdateRequest|SupersetAccountLookupRequest] -> Output[ProfilePreferenceResponse|SupersetAccountLookupResponse|bool]
  # @INVARIANT  Profile data integrity maintained, cache consistency with database state
  # @RATIONALE Thin coordinator — all sub-10-line delegating methods. Actual business logic lives
  #            in the injected sub-services.
> class ProfileService:
>     """Facade composing preference, lookup, and security services."""
  
      # region init [TYPE Function]
      # @BRIEF Initialize facade and create sub-services.
      # @PRE  db session is active and config_manager supports get_environments().
      # @POST  All sub-services are initialized and ready.
>     def __init__(self, db: Session, config_manager: Any, plugin_loader: Any = None):
>         self.preference_service = ProfilePreferenceService(db, config_manager, plugin_loader)
>         self.lookup_service = SupersetLookupService(config_manager)
>         self.security_badge_service = SecurityBadgeService(plugin_loader)
>         self.db = db
>         self.config_manager = config_manager
>         self.plugin_loader = plugin_loader
  
      # endregion init
  
      # region get_my_preference [TYPE Function]
      # @BRIEF Delegate to ProfilePreferenceService.
>     def get_my_preference(self, current_user: User) -> ProfilePreferenceResponse:
>         return self.preference_service.get_my_preference(current_user)
  
      # endregion get_my_preference
  
      # region get_dashboard_filter_binding [TYPE Function]
      # @BRIEF Delegate to ProfilePreferenceService.
>     def get_dashboard_filter_binding(self, current_user: User) -> dict:
>         return self.preference_service.get_dashboard_filter_binding(current_user)
  
      # endregion get_dashboard_filter_binding
  
      # region update_my_preference [TYPE Function]
      # @BRIEF Delegate to ProfilePreferenceService.
>     def update_my_preference(
>         self,
>         current_user: User,
>         payload: ProfilePreferenceUpdateRequest,
>         target_user_id: str | None = None,
>     ) -> ProfilePreferenceResponse:
>         return self.preference_service.update_my_preference(
>             current_user, payload, target_user_id
>         )
  
      # endregion update_my_preference
  
      # region lookup_superset_accounts [TYPE Function]
      # @BRIEF Delegate to SupersetLookupService.
      # @SIDE_EFFECT Асинхронный HTTP-вызов к Superset API.
>     async def lookup_superset_accounts(
>         self,
>         current_user: User,
>         request: SupersetAccountLookupRequest,
>     ) -> SupersetAccountLookupResponse:
>         return await self.lookup_service.lookup_superset_accounts(current_user, request)
  
      # endregion lookup_superset_accounts
  
      # region matches_dashboard_actor [TYPE Function]
      # @BRIEF Apply trim+case-insensitive actor match across owners OR modified_by.
      # @PRE  bound_username can be empty; owners may contain mixed payload.
      # @POST  Returns True when normalized username matches owners or modified_by.
>     def matches_dashboard_actor(
>         self,
>         bound_username: str | None,
>         owners: Iterable[Any] | None,
>         modified_by: str | None,
>     ) -> bool:
>         normalized_actor = normalize_username(bound_username)
>         if not normalized_actor:
>             return False
  
>         owner_tokens = normalize_owner_tokens(owners)
>         modified_token = normalize_username(modified_by)
  
>         if normalized_actor in owner_tokens:
>             return True
>         if modified_token and normalized_actor == modified_token:
>             return True
>         return False
  
      # endregion matches_dashboard_actor
  
  
  # #endregion ProfileService
  
  # #endregion profile_service
