# #region security_badge_service [C:4] [TYPE Module] [SEMANTICS profile,security,permissions,badges]
# @BRIEF Builds security summary and permission badges for profile UI — role extraction,
#        permission pair collection, and catalog formatting.
# @LAYER Domain
# @RELATION DEPENDS_ON -> [User]
# @RELATION DEPENDS_ON -> [discover_declared_permissions]
# @RELATION DEPENDS_ON -> [ProfileUtils]
# @RATIONALE Extracted from ProfileService to satisfy INV_7. Security badge construction
#            is a distinct concern with its own dependencies (discover_declared_permissions,
#            plugin_loader) and can be tested independently.
# @REJECTED Keeping security badge logic inside ProfileService was rejected — it adds
#            plugin_loader coupling to preference operations that do not need it and
#            inflates the class past 150 lines.
# @PRE Plugin loader may be None; user must have roles/permissions graph.
# @POST Returns deterministic security projection for profile UI with sorted permissions.
# @SIDE_EFFECT Reads plugin permissions via discover_declared_permissions when plugin_loader is set.

from typing import Any

from ..core.logger import belief_scope, logger
from ..models.auth import User
from ..schemas.profile import ProfilePermissionState, ProfileSecuritySummary
from .profile_utils import sanitize_text
from .rbac_permission_catalog import discover_declared_permissions


# #region SecurityBadgeService [C:4] [TYPE Class] [SEMANTICS security,permission,badge,profile]
# @BRIEF Builds security summary with role names and permission badges for profile UI display.
# @RELATION DEPENDS_ON -> [User]
# @RELATION CALLS -> [discover_declared_permissions]
# @PRE plugin_loader may be None for degraded permission discovery.
# @POST build_security_summary returns ProfileSecuritySummary with deterministic sorted permissions.
class SecurityBadgeService:
    """Builds security summary with role names and permission badges."""

    # #region __init__ [TYPE Function]
    # @BRIEF Initialize service with optional plugin loader for permission discovery.
    def __init__(self, plugin_loader: Any = None):
        self.plugin_loader = plugin_loader
    # #endregion __init__

    # #region build_security_summary [TYPE Function]
    # @BRIEF Build read-only security snapshot with role and permission badges.
    # @PRE current_user is authenticated.
    # @POST Returns deterministic security projection for profile UI.
    def build_security_summary(self, current_user: User) -> ProfileSecuritySummary:
        with belief_scope("SecurityBadgeService.build_security_summary"):
            role_names_set: set[str] = set()
            roles = getattr(current_user, "roles", []) or []
            for role in roles:
                normalized_role_name = sanitize_text(getattr(role, "name", None))
                if normalized_role_name:
                    role_names_set.add(normalized_role_name)
            role_names = sorted(role_names_set)

            is_admin = any(str(role_name).lower() == "admin" for role_name in role_names)
            user_permission_pairs = self._collect_user_permission_pairs(current_user)

            declared_permission_pairs: set[tuple[str, str]] = set()
            try:
                discovered_permissions = discover_declared_permissions(
                    plugin_loader=self.plugin_loader
                )
                for resource, action in discovered_permissions:
                    normalized_resource = sanitize_text(resource)
                    normalized_action = str(action or "").strip().upper()
                    if normalized_resource and normalized_action:
                        declared_permission_pairs.add(
                            (normalized_resource, normalized_action)
                        )
            except Exception as discovery_error:
                logger.explore(
                    "Failed to build declared permission catalog",
                    extra={"error": str(discovery_error), "src": "SecurityBadgeService.build_security_summary"},
                )

            if not declared_permission_pairs:
                declared_permission_pairs = set(user_permission_pairs)

            sorted_permission_pairs = sorted(
                declared_permission_pairs,
                key=lambda pair: (pair[0], pair[1]),
            )
            permission_states = [
                ProfilePermissionState(
                    key=self._format_permission_key(resource, action),
                    allowed=bool(is_admin or (resource, action) in user_permission_pairs),
                )
                for resource, action in sorted_permission_pairs
            ]

            auth_source = sanitize_text(getattr(current_user, "auth_source", None))
            current_role = "Admin" if is_admin else (role_names[0] if role_names else None)

            return ProfileSecuritySummary(
                read_only=True,
                auth_source=auth_source,
                current_role=current_role,
                role_source=auth_source,
                roles=role_names,
                permissions=permission_states,
            )
    # #endregion build_security_summary

    # #region _collect_user_permission_pairs [TYPE Function]
    # @BRIEF Collect effective permission tuples from current user's roles.
    # @PRE current_user can include role/permission graph.
    # @POST Returns unique normalized (resource, ACTION) tuples.
    def _collect_user_permission_pairs(
        self, current_user: User
    ) -> set[tuple[str, str]]:
        collected: set[tuple[str, str]] = set()
        roles = getattr(current_user, "roles", []) or []
        for role in roles:
            permissions = getattr(role, "permissions", []) or []
            for permission in permissions:
                resource = sanitize_text(getattr(permission, "resource", None))
                action = str(getattr(permission, "action", "") or "").strip().upper()
                if resource and action:
                    collected.add((resource, action))
        return collected
    # #endregion _collect_user_permission_pairs

    # #region _format_permission_key [C:1] [TYPE Function]
    # @BRIEF Convert normalized permission pair to compact UI key.
    def _format_permission_key(self, resource: str, action: str) -> str:
        normalized_resource = sanitize_text(resource) or ""
        normalized_action = str(action or "").strip().upper()
        if normalized_action == "READ":
            return normalized_resource
        return f"{normalized_resource}:{normalized_action.lower()}"
    # #endregion _format_permission_key
# #endregion SecurityBadgeService
# #endregion security_badge_service
