# #region AuthRepositoryModule [C:5] [TYPE Module] [SEMANTICS sqlalchemy, auth, search, user, auth-repository]
# @BRIEF Data access layer for authentication and user preference entities.
# @LAYER Domain
# @RELATION DEPENDS_ON -> [AuthModels]
# @RELATION DEPENDS_ON -> [ProfileModels]
# @RELATION DEPENDS_ON -> [belief_scope]
# @INVARIANT  All database read/write operations must execute via the injected SQLAlchemy session boundary.
# @DATA_CONTRACT  Input[EXT:Library:sqlalchemy.orm.Session] -> Output[User|Role|Permission|UserDashboardPreference access]
# @PRE  Database connection is active.
# @POST  Provides valid access to identity data.
# @SIDE_EFFECT  Executes database read queries through the injected SQLAlchemy session boundary.

from sqlalchemy.orm import Session, selectinload

from ...models.auth import ADGroupMapping, Permission, Role, User
from ...models.profile import UserDashboardPreference
from ..logger import belief_scope, logger


# #region AuthRepository [TYPE Class]
# @BRIEF Provides low-level CRUD operations for identity and authorization records.
# @PRE  Database session is bound.
# @POST  Entity instances returned safely.
# @SIDE_EFFECT  Performs database reads.
# @RELATION DEPENDS_ON -> [AuthModels]
class AuthRepository:
    def __init__(self, db: Session):
        self.db = db
    # #region get_user_by_id [TYPE Function]
    # @PURPOSE: Retrieve user by UUID.
    # @PRE  user_id is a valid UUID string.
    # @POST  Returns User object if found, else None.
    # @RELATION DEPENDS_ON -> [User]
    def get_user_by_id(self, user_id: str) -> User | None:
        with belief_scope("AuthRepository.get_user_by_id"):
            logger.reason(f"Fetching user by id: {user_id}")
            result = self.db.query(User).filter(User.id == user_id).first()
            logger.reflect(f"User found: {result is not None}")
            return result
    # #endregion get_user_by_id
    # #region get_user_by_username [TYPE Function]
    # @PURPOSE: Retrieve user by username.
    # @PRE  username is a non-empty string.
    # @POST  Returns User object if found, else None.
    # @RELATION DEPENDS_ON -> [User]
    def get_user_by_username(self, username: str) -> User | None:
        with belief_scope("AuthRepository.get_user_by_username"):
            logger.reason(f"Fetching user by username: {username}")
            result = self.db.query(User).filter(User.username == username).first()
            logger.reflect(f"User found: {result is not None}")
            return result
    # #endregion get_user_by_username
    # #region get_role_by_id [TYPE Function]
    # @PURPOSE: Retrieve role by UUID with permissions preloaded.
    # @RELATION DEPENDS_ON -> [Role]
    # @RELATION DEPENDS_ON -> [Permission]
    def get_role_by_id(self, role_id: str) -> Role | None:
        with belief_scope("AuthRepository.get_role_by_id"):
            return (
                self.db.query(Role)
                .options(selectinload(Role.permissions))
                .filter(Role.id == role_id)
                .first()
            )
    # #endregion get_role_by_id
    # #region get_role_by_name [TYPE Function]
    # @PURPOSE: Retrieve role by unique name.
    # @RELATION DEPENDS_ON -> [Role]
    def get_role_by_name(self, name: str) -> Role | None:
        with belief_scope("AuthRepository.get_role_by_name"):
            return self.db.query(Role).filter(Role.name == name).first()
    # #endregion get_role_by_name
    # #region get_permission_by_id [TYPE Function]
    # @PURPOSE: Retrieve permission by UUID.
    # @RELATION DEPENDS_ON -> [Permission]
    def get_permission_by_id(self, permission_id: str) -> Permission | None:
        with belief_scope("AuthRepository.get_permission_by_id"):
            return (
                self.db.query(Permission).filter(Permission.id == permission_id).first()
            )
    # #endregion get_permission_by_id
    # #region get_permission_by_resource_action [TYPE Function]
    # @PURPOSE: Retrieve permission by resource and action tuple.
    # @RELATION DEPENDS_ON -> [Permission]
    def get_permission_by_resource_action(
        self, resource: str, action: str
    ) -> Permission | None:
        with belief_scope("AuthRepository.get_permission_by_resource_action"):
            return (
                self.db.query(Permission)
                .filter(Permission.resource == resource, Permission.action == action)
                .first()
            )
    # #endregion get_permission_by_resource_action
    # #region list_permissions [TYPE Function]
    # @PURPOSE: List all system permissions.
    # @RELATION DEPENDS_ON -> [Permission]
    def list_permissions(self) -> list[Permission]:
        with belief_scope("AuthRepository.list_permissions"):
            return self.db.query(Permission).all()
    # #endregion list_permissions
    # #region get_user_dashboard_preference [TYPE Function]
    # @PURPOSE: Retrieve dashboard filters/preferences for a user.
    # @RELATION DEPENDS_ON -> [UserDashboardPreference]
    def get_user_dashboard_preference(
        self, user_id: str
    ) -> UserDashboardPreference | None:
        with belief_scope("AuthRepository.get_user_dashboard_preference"):
            return (
                self.db.query(UserDashboardPreference)
                .filter(UserDashboardPreference.user_id == user_id)
                .first()
            )
    # #endregion get_user_dashboard_preference
    # #region get_roles_by_ad_groups [TYPE Function]
    # @PURPOSE: Retrieve roles that match a list of AD group names.
    # @PRE  groups is a list of strings representing AD group identifiers.
    # @POST  Returns a list of Role objects mapped to the provided AD groups.
    # @RELATION DEPENDS_ON -> [Role]
    # @RELATION DEPENDS_ON -> [ADGroupMapping]
    def get_roles_by_ad_groups(self, groups: list[str]) -> list[Role]:
        with belief_scope("AuthRepository.get_roles_by_ad_groups"):
            logger.reason(f"Fetching roles for AD groups: {groups}")
            if not groups:
                return []
            return (
                self.db.query(Role)
                .join(ADGroupMapping)
                .filter(ADGroupMapping.ad_group.in_(groups))
                .all()
            )
    # #endregion get_roles_by_ad_groups
# #endregion AuthRepository
# #endregion AuthRepositoryModule
