"""Terraform HCL parser — extract resources from .tf files."""

from __future__ import annotations

import re
from pathlib import Path

from ..models import InfraDiagram, InfraEdge, InfraGroup, InfraNode, NodeType, SourceType

# Map Terraform resource types to NodeType
_RESOURCE_MAP: dict[str, NodeType] = {
    # AWS Compute
    "aws_instance": NodeType.VM,
    "aws_ecs_cluster": NodeType.CONTAINER,
    "aws_ecs_service": NodeType.CONTAINER,
    "aws_ecs_task_definition": NodeType.CONTAINER,
    "aws_lambda_function": NodeType.SERVERLESS,
    "aws_autoscaling_group": NodeType.COMPUTE,
    "aws_eks_cluster": NodeType.CONTAINER,
    "aws_eks_node_group": NodeType.CONTAINER,
    # AWS Storage
    "aws_s3_bucket": NodeType.STORAGE,
    "aws_dynamodb_table": NodeType.DATABASE,
    "aws_rds_instance": NodeType.DATABASE,
    "aws_rds_cluster": NodeType.DATABASE,
    "aws_elasticache_cluster": NodeType.CACHE,
    "aws_sqs_queue": NodeType.QUEUE,
    "aws_sns_topic": NodeType.QUEUE,
    "aws_ebs_volume": NodeType.VOLUME,
    # AWS Network
    "aws_vpc": NodeType.NETWORK,
    "aws_subnet": NodeType.SUBNET,
    "aws_security_group": NodeType.FIREWALL,
    "aws_lb": NodeType.LOAD_BALANCER,
    "aws_alb": NodeType.LOAD_BALANCER,
    "aws_cloudfront_distribution": NodeType.CDN,
    "aws_route53_zone": NodeType.DNS,
    "aws_route53_record": NodeType.DNS,
    "aws_nat_gateway": NodeType.GATEWAY,
    "aws_internet_gateway": NodeType.GATEWAY,
    "aws_api_gateway_rest_api": NodeType.GATEWAY,
    "aws_apigatewayv2_api": NodeType.GATEWAY,
    # AWS Security
    "aws_iam_role": NodeType.IAM,
    "aws_iam_policy": NodeType.IAM,
    "aws_iam_user": NodeType.IAM,
    "aws_secretsmanager_secret": NodeType.SECRET,
    "aws_acm_certificate": NodeType.CERTIFICATE,
    "aws_kms_key": NodeType.SECRET,
    # AWS Monitoring
    "aws_cloudwatch_log_group": NodeType.LOGGING,
    "aws_cloudwatch_metric_alarm": NodeType.MONITORING,
    # Azure
    "azurerm_resource_group": NodeType.NAMESPACE,
    "azurerm_virtual_network": NodeType.NETWORK,
    "azurerm_subnet": NodeType.SUBNET,
    "azurerm_virtual_machine": NodeType.VM,
    "azurerm_linux_virtual_machine": NodeType.VM,
    "azurerm_windows_virtual_machine": NodeType.VM,
    "azurerm_container_group": NodeType.CONTAINER,
    "azurerm_kubernetes_cluster": NodeType.CONTAINER,
    "azurerm_function_app": NodeType.SERVERLESS,
    "azurerm_storage_account": NodeType.STORAGE,
    "azurerm_sql_server": NodeType.DATABASE,
    "azurerm_cosmosdb_account": NodeType.DATABASE,
    "azurerm_redis_cache": NodeType.CACHE,
    "azurerm_lb": NodeType.LOAD_BALANCER,
    "azurerm_application_gateway": NodeType.GATEWAY,
    "azurerm_dns_zone": NodeType.DNS,
    "azurerm_key_vault": NodeType.SECRET,
    # GCP
    "google_compute_instance": NodeType.VM,
    "google_container_cluster": NodeType.CONTAINER,
    "google_cloud_run_service": NodeType.SERVERLESS,
    "google_cloudfunctions_function": NodeType.SERVERLESS,
    "google_storage_bucket": NodeType.STORAGE,
    "google_sql_database_instance": NodeType.DATABASE,
    "google_redis_instance": NodeType.CACHE,
    "google_compute_network": NodeType.NETWORK,
    "google_compute_subnetwork": NodeType.SUBNET,
    "google_compute_firewall": NodeType.FIREWALL,
    "google_dns_managed_zone": NodeType.DNS,
    "google_kms_key_ring": NodeType.SECRET,
    "google_pubsub_topic": NodeType.QUEUE,
}


def parse_terraform(path: str) -> InfraDiagram:
    """Parse Terraform files from a directory or single file."""
    diagram = InfraDiagram(
        title="Terraform Infrastructure",
        source_type=SourceType.TERRAFORM,
    )

    p = Path(path)
    tf_files = []
    if p.is_file() and p.suffix == ".tf":
        tf_files = [p]
    elif p.is_dir():
        tf_files = sorted(p.glob("**/*.tf"))

    for tf_file in tf_files:
        diagram.source_files.append(str(tf_file))
        _parse_tf_file(tf_file, diagram)

    # Auto-detect edges from references
    _detect_edges(diagram)

    # Group by provider
    _group_by_provider(diagram)

    return diagram


def _parse_tf_file(tf_file: Path, diagram: InfraDiagram) -> None:
    """Parse a single .tf file."""
    content = tf_file.read_text(encoding="utf-8", errors="ignore")

    # Match resource blocks: resource "type" "name" {
    pattern = re.compile(r'resource\s+"([^"]+)"\s+"([^"]+)"\s*\{', re.MULTILINE)

    for match in pattern.finditer(content):
        res_type = match.group(1)
        res_name = match.group(2)

        node_type = _RESOURCE_MAP.get(res_type, NodeType.UNKNOWN)
        provider = _detect_provider(res_type)

        node = InfraNode(
            id=f"{res_type}.{res_name}",
            name=res_name,
            node_type=node_type,
            provider=provider,
            source_file=str(tf_file),
            properties={"resource_type": res_type},
        )
        diagram.add_node(node)

    # Also parse data sources
    data_pattern = re.compile(r'data\s+"([^"]+)"\s+"([^"]+)"\s*\{', re.MULTILINE)
    for match in data_pattern.finditer(content):
        res_type = match.group(1)
        res_name = match.group(2)
        provider = _detect_provider(res_type)

        node = InfraNode(
            id=f"data.{res_type}.{res_name}",
            name=f"{res_name} (data)",
            node_type=NodeType.CONFIG,
            provider=provider,
            source_file=str(tf_file),
            properties={"resource_type": res_type, "is_data": True},
        )
        diagram.add_node(node)


def _detect_provider(resource_type: str) -> str:
    """Detect cloud provider from resource type."""
    if resource_type.startswith("aws_"):
        return "aws"
    if resource_type.startswith("azurerm_"):
        return "azure"
    if resource_type.startswith("google_"):
        return "gcp"
    if resource_type.startswith("kubernetes_"):
        return "kubernetes"
    return "other"


def _detect_edges(diagram: InfraDiagram) -> None:
    """Detect edges from Terraform references."""
    node_ids = {n.id for n in diagram.nodes}

    for node in diagram.nodes:
        res_type = node.properties.get("resource_type", "")

        # Subnet -> VPC
        if "subnet" in res_type and any("vpc" in nid or "network" in nid for nid in node_ids):
            for nid in node_ids:
                if "vpc" in nid or ("network" in nid and "subnet" not in nid):
                    diagram.add_edge(InfraEdge(source=node.id, target=nid, label="in"))
                    break

        # Instances/services -> subnet
        if node.node_type in (NodeType.VM, NodeType.CONTAINER, NodeType.SERVERLESS):
            for nid in node_ids:
                if "subnet" in nid:
                    diagram.add_edge(InfraEdge(source=node.id, target=nid, label="in"))
                    break

        # Load balancer -> compute/container
        if node.node_type == NodeType.LOAD_BALANCER:
            for n2 in diagram.nodes:
                if n2.node_type in (NodeType.VM, NodeType.CONTAINER, NodeType.SERVERLESS) and n2.id != node.id:
                    diagram.add_edge(InfraEdge(source=node.id, target=n2.id, label="routes to"))

        # Gateway -> network
        if node.node_type == NodeType.GATEWAY:
            for nid in node_ids:
                if "vpc" in nid or "network" in nid:
                    diagram.add_edge(InfraEdge(source=node.id, target=nid, label="attached"))
                    break


def _group_by_provider(diagram: InfraDiagram) -> None:
    """Group nodes by cloud provider."""
    providers: dict[str, list[str]] = {}
    for node in diagram.nodes:
        p = node.provider or "other"
        if p not in providers:
            providers[p] = []
        providers[p].append(node.id)

    for provider, ids in providers.items():
        if len(ids) > 1:
            diagram.add_group(InfraGroup(
                id=f"group_{provider}",
                name=provider.upper(),
                node_ids=ids,
            ))
