"""Helper functions for building PIM 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_pim_relationships(
    eligibilities: List[ResourceNode],
    resources: List[ResourceNode],
    entra_principals: List[ResourceNode],
    role_definitions: List[ResourceNode],
) -> List[ResourceRelationship]:
    """Build edges connecting PIM eligibilities to principals, resources, and role definitions.

    Args:
        eligibilities: List of PIM eligibility nodes
        resources: List of Azure resource nodes
        entra_principals: List of Entra ID principal nodes (users, groups, service principals)
        role_definitions: List of role definition nodes

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

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

    # 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 PIM relationships",
        extra={
            "context": {
                "eligibilities": len(eligibilities),
                "resources": len(resources),
                "principals": len(entra_principals),
                "role_definitions": len(role_definitions),
            }
        },
    )

    for eligibility in eligibilities:
        # Extract eligibility properties
        props = eligibility.properties or {}
        principal_id = props.get("principalId")
        scope = props.get("scope") or props.get("directoryScopeId")
        role_definition_id = props.get("roleDefinitionId")
        eligibility_type = props.get("eligibilityType", "Unknown")

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

        # Edge: RoleEligibility -> Resource ("eligible_for")
        # Parse scope to find target resource
        if scope and eligibility_type == "AzureResource":
            # Azure Resource eligibilities have ARM scope paths
            scope_lower = scope.lower()
            target_resource = resource_by_id.get(scope_lower)

            if target_resource:
                relationships.append(
                    ResourceRelationship(
                        source_id=eligibility.id,
                        target_id=target_resource.id,
                        relation_type="eligible_for",
                        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, "eligibility_id": eligibility.id}},
                )
        elif scope and eligibility_type == "EntraRole":
            # Entra role eligibilities have directory scope (typically "/" for directory-wide)
            # We don't link these to resources, as they're directory roles
            LOGGER.debug(
                "Entra role eligibility (directory scope, not linked to ARM resources)",
                extra={"context": {"scope": scope, "eligibility_id": eligibility.id}},
            )

        # Edge: RoleEligibility -> RoleDefinition ("eligible_via_role")
        if role_definition_id:
            role_def_id_lower = role_definition_id.lower()
            role_def = role_def_by_id.get(role_def_id_lower)

            if role_def:
                relationships.append(
                    ResourceRelationship(
                        source_id=eligibility.id,
                        target_id=role_def.id,
                        relation_type="eligible_via_role",
                        weight=1.0,
                    )
                )
            else:
                LOGGER.debug(
                    "Role definition not found",
                    extra={
                        "context": {
                            "role_definition_id": role_definition_id,
                            "eligibility_id": eligibility.id,
                        }
                    },
                )

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

    return relationships


def filter_high_privilege_eligibilities(
    eligibilities: List[ResourceNode],
) -> List[ResourceNode]:
    """Filter PIM eligibilities for high-privilege roles.

    Args:
        eligibilities: List of PIM eligibility nodes

    Returns:
        Filtered list containing only high-privilege eligibilities
    """
    high_privilege_roles = {
        "owner",
        "contributor",
        "user access administrator",
        "security admin",
        "security operator",
        "global administrator",
        "privileged role administrator",
        "application administrator",
        "authentication administrator",
        "billing administrator",
        "cloud application administrator",
        "exchange administrator",
        "helpdesk administrator",
        "password administrator",
        "privileged authentication administrator",
        "security administrator",
        "sharepoint administrator",
        "user administrator",
    }

    filtered = []
    for eligibility in eligibilities:
        props = eligibility.properties or {}
        role_def_id = props.get("roleDefinitionId", "").lower()

        # Check if any high-privilege role name is in the role definition ID or name
        if any(priv_role in role_def_id for priv_role in high_privilege_roles):
            filtered.append(eligibility)

    return filtered


def get_pim_eligibility_summary(
    eligibilities: List[ResourceNode],
) -> Dict[str, int]:
    """Generate summary statistics for PIM eligibilities.

    Args:
        eligibilities: List of PIM eligibility nodes

    Returns:
        Dictionary with summary statistics
    """
    summary = {
        "total_eligibilities": len(eligibilities),
        "entra_role_eligibilities": 0,
        "azure_resource_eligibilities": 0,
        "active_eligibilities": 0,
        "expired_eligibilities": 0,
    }

    for eligibility in eligibilities:
        props = eligibility.properties or {}
        eligibility_type = props.get("eligibilityType", "Unknown")
        status = props.get("status", "").lower()

        if eligibility_type == "EntraRole":
            summary["entra_role_eligibilities"] += 1
        elif eligibility_type == "AzureResource":
            summary["azure_resource_eligibilities"] += 1

        if status in ["provisioned", "active"]:
            summary["active_eligibilities"] += 1
        elif status in ["expired", "revoked"]:
            summary["expired_eligibilities"] += 1

    return summary
