"""Tests for infra_diagram.parsers.terraform."""

from __future__ import annotations

import tempfile
from pathlib import Path

from infra_diagram.models import NodeType, SourceType
from infra_diagram.parsers.terraform import _RESOURCE_MAP, _detect_provider, parse_terraform

# ─── Resource map coverage ───────────────────────────────────────────

class TestResourceMap:
    def test_aws_compute_mapped(self):
        assert _RESOURCE_MAP["aws_instance"] == NodeType.VM
        assert _RESOURCE_MAP["aws_ecs_cluster"] == NodeType.CONTAINER
        assert _RESOURCE_MAP["aws_lambda_function"] == NodeType.SERVERLESS

    def test_aws_storage_mapped(self):
        assert _RESOURCE_MAP["aws_s3_bucket"] == NodeType.STORAGE
        assert _RESOURCE_MAP["aws_rds_instance"] == NodeType.DATABASE
        assert _RESOURCE_MAP["aws_elasticache_cluster"] == NodeType.CACHE
        assert _RESOURCE_MAP["aws_sqs_queue"] == NodeType.QUEUE

    def test_aws_network_mapped(self):
        assert _RESOURCE_MAP["aws_vpc"] == NodeType.NETWORK
        assert _RESOURCE_MAP["aws_subnet"] == NodeType.SUBNET
        assert _RESOURCE_MAP["aws_lb"] == NodeType.LOAD_BALANCER
        assert _RESOURCE_MAP["aws_security_group"] == NodeType.FIREWALL

    def test_azure_mapped(self):
        assert _RESOURCE_MAP["azurerm_virtual_machine"] == NodeType.VM
        assert _RESOURCE_MAP["azurerm_kubernetes_cluster"] == NodeType.CONTAINER
        assert _RESOURCE_MAP["azurerm_function_app"] == NodeType.SERVERLESS
        assert _RESOURCE_MAP["azurerm_storage_account"] == NodeType.STORAGE

    def test_gcp_mapped(self):
        assert _RESOURCE_MAP["google_compute_instance"] == NodeType.VM
        assert _RESOURCE_MAP["google_container_cluster"] == NodeType.CONTAINER
        assert _RESOURCE_MAP["google_storage_bucket"] == NodeType.STORAGE

    def test_map_count(self):
        assert len(_RESOURCE_MAP) >= 50


# ─── Provider detection ─────────────────────────────────────────────

class TestDetectProvider:
    def test_aws(self):
        assert _detect_provider("aws_instance") == "aws"

    def test_azure(self):
        assert _detect_provider("azurerm_virtual_machine") == "azure"

    def test_gcp(self):
        assert _detect_provider("google_compute_instance") == "gcp"

    def test_kubernetes(self):
        assert _detect_provider("kubernetes_namespace") == "kubernetes"

    def test_other(self):
        assert _detect_provider("random_pet") == "other"


# ─── Parsing ─────────────────────────────────────────────────────────

class TestParseTerraform:
    def _write_tf(self, tmpdir: str, content: str, name: str = "main.tf") -> str:
        fpath = Path(tmpdir) / name
        fpath.write_text(content, encoding="utf-8")
        return tmpdir

    def test_single_resource(self):
        tf = 'resource "aws_vpc" "main" {\n  cidr_block = "10.0.0.0/16"\n}\n'
        with tempfile.TemporaryDirectory() as d:
            self._write_tf(d, tf)
            diagram = parse_terraform(d)
            assert diagram.node_count >= 1
            assert diagram.source_type == SourceType.TERRAFORM
            n = diagram.get_node("aws_vpc.main")
            assert n is not None
            assert n.node_type == NodeType.NETWORK
            assert n.provider == "aws"

    def test_multiple_resources(self):
        tf = (
            'resource "aws_vpc" "v" { }\n'
            'resource "aws_subnet" "s" { }\n'
            'resource "aws_instance" "web" { }\n'
        )
        with tempfile.TemporaryDirectory() as d:
            self._write_tf(d, tf)
            diagram = parse_terraform(d)
            assert diagram.node_count >= 3

    def test_data_source_parsed(self):
        tf = 'data "aws_ami" "latest" {\n  most_recent = true\n}\n'
        with tempfile.TemporaryDirectory() as d:
            self._write_tf(d, tf)
            diagram = parse_terraform(d)
            n = diagram.get_node("data.aws_ami.latest")
            assert n is not None
            assert n.node_type == NodeType.CONFIG
            assert n.properties.get("is_data") is True

    def test_edge_detection_subnet_to_vpc(self):
        tf = (
            'resource "aws_vpc" "main" { }\n'
            'resource "aws_subnet" "pub" { }\n'
        )
        with tempfile.TemporaryDirectory() as d:
            self._write_tf(d, tf)
            diagram = parse_terraform(d)
            edges = [e for e in diagram.edges if e.source == "aws_subnet.pub"]
            assert len(edges) > 0

    def test_lb_to_compute_edge(self):
        tf = (
            'resource "aws_lb" "web" { }\n'
            'resource "aws_instance" "app" { }\n'
        )
        with tempfile.TemporaryDirectory() as d:
            self._write_tf(d, tf)
            diagram = parse_terraform(d)
            lb_edges = [e for e in diagram.edges if e.source == "aws_lb.web"]
            assert len(lb_edges) > 0

    def test_provider_grouping(self):
        tf = (
            'resource "aws_vpc" "v" { }\n'
            'resource "aws_instance" "i" { }\n'
        )
        with tempfile.TemporaryDirectory() as d:
            self._write_tf(d, tf)
            diagram = parse_terraform(d)
            assert len(diagram.groups) > 0

    def test_empty_directory(self):
        with tempfile.TemporaryDirectory() as d:
            diagram = parse_terraform(d)
            assert diagram.node_count == 0

    def test_single_file_mode(self):
        tf = 'resource "aws_s3_bucket" "data" { }\n'
        with tempfile.TemporaryDirectory() as d:
            fpath = Path(d) / "main.tf"
            fpath.write_text(tf, encoding="utf-8")
            diagram = parse_terraform(str(fpath))
            assert diagram.node_count >= 1

    def test_unknown_resource_type(self):
        tf = 'resource "some_custom_thing" "x" { }\n'
        with tempfile.TemporaryDirectory() as d:
            self._write_tf(d, tf)
            diagram = parse_terraform(d)
            n = diagram.get_node("some_custom_thing.x")
            assert n is not None
            assert n.node_type == NodeType.UNKNOWN

    def test_azure_resources(self):
        tf = (
            'resource "azurerm_resource_group" "rg" { }\n'
            'resource "azurerm_virtual_network" "vnet" { }\n'
        )
        with tempfile.TemporaryDirectory() as d:
            self._write_tf(d, tf)
            diagram = parse_terraform(d)
            assert diagram.node_count >= 2
            rg = diagram.get_node("azurerm_resource_group.rg")
            assert rg is not None
            assert rg.provider == "azure"

    def test_source_files_tracked(self):
        tf = 'resource "aws_vpc" "v" { }\n'
        with tempfile.TemporaryDirectory() as d:
            self._write_tf(d, tf)
            diagram = parse_terraform(d)
            assert len(diagram.source_files) == 1

    def test_multiple_files(self):
        with tempfile.TemporaryDirectory() as d:
            (Path(d) / "vpc.tf").write_text('resource "aws_vpc" "v" { }\n', encoding="utf-8")
            (Path(d) / "ec2.tf").write_text('resource "aws_instance" "i" { }\n', encoding="utf-8")
            diagram = parse_terraform(d)
            assert diagram.node_count >= 2
            assert len(diagram.source_files) >= 2

    def test_gcp_resources(self):
        tf = 'resource "google_compute_instance" "vm" { }\n'
        with tempfile.TemporaryDirectory() as d:
            self._write_tf(d, tf)
            diagram = parse_terraform(d)
            n = diagram.get_node("google_compute_instance.vm")
            assert n is not None
            assert n.provider == "gcp"
