"""Azure resource enumeration logic."""

from __future__ import annotations

from typing import Any

from azure.core.credentials import TokenCredential

from ..adt_types import (
    AzureDiscoveryRequest,
    AzureDiscoveryResponse,
    ResourceNode,
)
from ..utils import (
    build_environment_config,
    ensure_subscription_ids,
    get_credential,
    query_resource_graph,
)
from ..utils.graph_helpers import build_graph_edges, ensure_unique_nodes
from ..utils.logging import get_logger

LOGGER = get_logger()


def _build_query(request: AzureDiscoveryRequest) -> str:
    clauses = ["resources"]
    filters = []

    if request.filter:
        discovery_filter = request.filter
        if discovery_filter.include_types:
            include_clause = " or ".join(
                f"tolower(type) == '{resource_type.lower()}'"
                for resource_type in discovery_filter.include_types
            )
            filters.append(f"({include_clause})")
        if discovery_filter.exclude_types:
            exclude_clause = " and ".join(
                f"tolower(type) != '{resource_type.lower()}'"
                for resource_type in discovery_filter.exclude_types
            )
            filters.append(f"({exclude_clause})")
        if discovery_filter.resource_groups:
            groups_clause = " or ".join(
                f"tolower(resourceGroup) == '{group.lower()}'"
                for group in discovery_filter.resource_groups
            )
            filters.append(f"({groups_clause})")
        if discovery_filter.required_tags:
            tag_clause = " and ".join(
                f"tags['{key}'] =~ '{value}'"
                for key, value in discovery_filter.required_tags.items()
            )
            filters.append(f"({tag_clause})")

    if filters:
        clauses.append("| where " + " and ".join(filters))

    clauses.append(
        "| project id, name, type, location, resourceGroup,"
        " subscriptionId, tags, properties"
    )
    return " ".join(clauses)


def _to_node(payload: dict[str, Any]) -> ResourceNode:
    dependencies = []
    properties = payload.get("properties") or {}
    raw_dependencies = properties.get("dependencies") or []
    for dependency in raw_dependencies:
        resource_id = dependency.get("resourceId")
        if resource_id:
            dependencies.append(resource_id)

    return ResourceNode(
        id=payload["id"],
        name=payload.get("name", payload["id"].split("/")[-1]),
        type=payload.get("type", "unknown"),
        location=payload.get("location"),
        subscription_id=payload.get("subscriptionId"),
        resource_group=payload.get("resourceGroup"),
        tags=payload.get("tags") or {},
        dependencies=dependencies,
    )


async def enumerate_azure_resources(
    request: AzureDiscoveryRequest,
    credential: TokenCredential | None = None,
) -> AzureDiscoveryResponse:
    """Return normalized Azure resources for the provided tenant.

    When credential is provided (e.g. from an embedding app like auto_iac), it is
    used with the request's environment so sovereign clouds work. Otherwise the
    default credential chain is built from the request.
    """
    if not request:
        raise ValueError("request cannot be None")

    environment_config = build_environment_config(request.environment)
    if credential is None:
        credential = get_credential(request, environment_config)
    subscription_ids = await ensure_subscription_ids(
        request, credential, base_url=environment_config.resource_manager
    )
    query = _build_query(request)
    raw_resources = await query_resource_graph(
        credential=credential,
        query=query,
        subscriptions=subscription_ids,
        batch_size=request.max_batch_size,
        base_url=environment_config.resource_manager,
        scale_controls=request.scale_controls,
    )
    nodes = ensure_unique_nodes(_to_node(item) for item in raw_resources)
    relationships = build_graph_edges(nodes, request.include_relationships)

    LOGGER.info(
        "Enumeration completed",
        extra={
            "context": {
                "tenant_id": request.tenant_id,
                "nodes": len(nodes),
                "relationships": len(relationships),
            }
        },
    )
    return AzureDiscoveryResponse(
        tenant_id=request.tenant_id,
        discovered_subscriptions=subscription_ids,
        nodes=nodes,
        relationships=relationships,
        total_resources=len(nodes),
    )
