"""Helper functions for building RBAC relationship graphs."""

from typing import List, Dict

from ..adt_types.models import ResourceNode, ResourceRelationship
from ..utils.logging import get_logger

LOGGER = get_logger()


def build_rbac_relationships(
    assignments: List[ResourceNode],
    resources: List[ResourceNode],
    entra_principals: List[ResourceNode],
) -> List[ResourceRelationship]:
    """Build edges connecting assignments to principals and resources.

    Args:
        assignments: List of role assignment nodes
        resources: List of Azure resource nodes
        entra_principals: List of Entra ID principal nodes (users, groups, service principals)

    Returns:
        List of relationship edges connecting RBAC entities
    """
    relationships = []

    # Build lookup maps for efficient matching
    resource_by_id = {r.id.lower(): r for r in resources}

    # Build principal lookup - extract object ID from various ID formats
    principal_by_id: Dict[str, ResourceNode] = {}
    for p in entra_principals:
        if p.type in [
            "Microsoft.Graph/User",
            "Microsoft.Graph/Group",
            "Microsoft.Graph/ServicePrincipal",
        ]:
            # Extract object ID from various namespace formats
            # Examples: "graph://users/{id}", "graph://servicePrincipals/{id}", etc.
            if "/" in p.id:
                object_id = p.id.split("/")[-1]
                principal_by_id[object_id.lower()] = p
            else:
                # Direct ID
                principal_by_id[p.id.lower()] = p

    LOGGER.info(
        "Building RBAC relationships",
        extra={
            "context": {
                "assignments": len(assignments),
                "resources": len(resources),
                "principals": len(entra_principals),
            }
        },
    )

    for assignment in assignments:
        # Extract assignment properties
        props = assignment.properties or {}
        principal_id = props.get("principalId")
        scope = props.get("scope")
        role_definition_id = props.get("roleDefinitionId")

        # Edge: Principal -> RoleAssignment ("has_role_assignment")
        if principal_id:
            principal = principal_by_id.get(principal_id.lower())
            if principal:
                relationships.append(
                    ResourceRelationship(
                        source_id=principal.id,
                        target_id=assignment.id,
                        relation_type="has_role_assignment",
                        weight=1.0,
                    )
                )
            else:
                LOGGER.debug(
                    "Principal not found in Entra principals",
                    extra={
                        "context": {
                            "principal_id": principal_id,
                            "assignment_id": assignment.id,
                        }
                    },
                )

        # Edge: RoleAssignment -> Resource ("grants_access_to")
        # Parse scope to find target resource
        if scope:
            # Normalize scope for lookup
            scope_lower = scope.lower()
            target_resource = resource_by_id.get(scope_lower)

            if target_resource:
                relationships.append(
                    ResourceRelationship(
                        source_id=assignment.id,
                        target_id=target_resource.id,
                        relation_type="grants_access_to",
                        weight=1.0,
                    )
                )
            else:
                # Scope might be at subscription or RG level, not a specific resource
                LOGGER.debug(
                    "Scope does not match a specific resource",
                    extra={"context": {"scope": scope, "assignment_id": assignment.id}},
                )

        # Edge: RoleAssignment -> RoleDefinition ("uses_role_definition")
        if role_definition_id:
            relationships.append(
                ResourceRelationship(
                    source_id=assignment.id,
                    target_id=role_definition_id,
                    relation_type="uses_role_definition",
                    weight=1.0,
                )
            )

    LOGGER.info(
        "RBAC relationships built",
        extra={"context": {"total_relationships": len(relationships)}},
    )

    return relationships


def filter_high_privilege_assignments(
    assignments: List[ResourceNode],
) -> List[ResourceNode]:
    """Filter role assignments for high-privilege roles.

    Args:
        assignments: List of role assignment nodes

    Returns:
        Filtered list containing only high-privilege assignments
    """
    high_privilege_roles = {
        "owner",
        "contributor",
        "user access administrator",
        "security admin",
        "security operator",
        "global administrator",
    }

    filtered = []
    for assignment in assignments:
        props = assignment.properties or {}
        role_name = props.get("roleDefinitionName", "").lower()

        if any(priv_role in role_name for priv_role in high_privilege_roles):
            filtered.append(assignment)

    return filtered
