# VM Deployment Module for Besu Network
# Deploys Besu nodes on Virtual Machines or VM Scale Sets with Docker Engine
# Variables are defined in variables.tf

# Network Interface
resource "azurerm_network_interface" "besu_node" {
  count               = var.use_scale_set ? 0 : var.node_count
  name                = "${var.cluster_name}-${var.node_type}-nic-${count.index}"
  location            = var.location
  resource_group_name = var.resource_group_name

  ip_configuration {
    name                          = "internal"
    subnet_id                     = var.subnet_id
    private_ip_address_allocation = "Dynamic"
    # Only sentry and RPC nodes get public IPs; besu-node uses private IPs only
    public_ip_address_id          = (var.node_type == "sentry" || var.node_type == "rpc") ? azurerm_public_ip.besu_node[count.index].id : null
  }

  tags = merge(var.tags, {
    NodeType  = var.node_type
    NodeIndex = count.index
  })
}

# Associate NSG with NIC
resource "azurerm_network_interface_security_group_association" "besu_node" {
  count                     = var.use_scale_set ? 0 : var.node_count
  network_interface_id      = azurerm_network_interface.besu_node[count.index].id
  network_security_group_id = var.network_security_group_id
}

# Public IP for sentry and RPC nodes only (besu-node uses private IPs only)
# Note: Phase 1 backend VMs use private IPs only; Nginx proxy connects via Cloudflare Tunnel
resource "azurerm_public_ip" "besu_node" {
  count               = var.use_scale_set ? 0 : (var.node_type == "sentry" || var.node_type == "rpc" ? var.node_count : 0)
  name                = "${var.cluster_name}-${var.node_type}-ip-${count.index}"
  location            = var.location
  resource_group_name = var.resource_group_name
  allocation_method   = "Static"
  sku                 = "Standard"

  tags = merge(var.tags, {
    NodeType = var.node_type
    NodeIndex = count.index
  })
}

# Virtual Machine
resource "azurerm_linux_virtual_machine" "besu_node" {
  count               = var.use_scale_set ? 0 : var.node_count
  name                = "${var.cluster_name}-${var.node_type}-${count.index}"
  location            = var.location
  resource_group_name = var.resource_group_name
  size                = var.vm_size
  admin_username      = var.admin_username

  network_interface_ids = [azurerm_network_interface.besu_node[count.index].id]

  admin_ssh_key {
    username   = var.admin_username
    public_key = var.ssh_public_key
  }

  os_disk {
    name                 = "${var.cluster_name}-${var.node_type}-disk-${count.index}"
    caching              = "ReadWrite"
    storage_account_type = var.storage_account_type
    disk_size_gb         = var.disk_size_gb
  }

  source_image_reference {
    publisher = "Canonical"
    offer     = "0001-com-ubuntu-server-jammy"
    sku       = "22_04-lts-gen2"
    version   = "latest"
  }

  dynamic "boot_diagnostics" {
    for_each = var.vm_enable_boot_diagnostics && var.storage_account_name != "" ? [1] : []
    content {
      storage_account_uri = var.storage_account_name != "" ? "https://${var.storage_account_name}.blob.core.windows.net/" : null
    }
  }

  dynamic "identity" {
    for_each = var.vm_enable_managed_identity ? [1] : []
    content {
      type = "SystemAssigned"
    }
  }

  custom_data = base64encode(templatefile(
    var.use_phase1_cloud_init ? "${path.module}/cloud-init-phase1.yaml" : "${path.module}/cloud-init.yaml",
    {
      node_type        = var.node_type
      node_index       = count.index
      cluster_name     = var.cluster_name
      key_vault_id     = var.key_vault_id
      genesis_file_path = var.genesis_file_path
      admin_username   = var.admin_username
    }
  ))

  tags = merge(var.tags, {
    NodeType  = var.node_type
    NodeIndex = count.index
  })

  depends_on = [azurerm_network_interface.besu_node]
}

# VM Scale Set (alternative to individual VMs)
resource "azurerm_linux_virtual_machine_scale_set" "besu_node" {
  count               = var.use_scale_set ? 1 : 0
  name                = "${var.cluster_name}-${var.node_type}-vmss"
  location            = var.location
  resource_group_name = var.resource_group_name
  sku                 = var.vm_size
  instances           = var.node_count
  admin_username      = var.admin_username

  admin_ssh_key {
    username   = var.admin_username
    public_key = var.ssh_public_key
  }

  source_image_reference {
    publisher = "Canonical"
    offer     = "0001-com-ubuntu-server-jammy"
    sku       = "22_04-lts-gen2"
    version   = "latest"
  }

  os_disk {
    storage_account_type = var.storage_account_type
    caching              = "ReadWrite"
    disk_size_gb         = var.disk_size_gb
  }

  network_interface {
    name    = "${var.cluster_name}-${var.node_type}-nic"
    primary = true

    ip_configuration {
      name      = "internal"
      primary   = true
      subnet_id = var.subnet_id
      
      # Only sentry and RPC nodes get public IPs; besu-node uses private IPs only
      # Match the logic used for individual VMs
      dynamic "public_ip_address" {
        for_each = (var.node_type == "sentry" || var.node_type == "rpc") ? [1] : []
        content {
          name = "${var.cluster_name}-${var.node_type}-public-ip"
        }
      }
    }
  }

  dynamic "identity" {
    for_each = var.vm_enable_managed_identity ? [1] : []
    content {
      type = "SystemAssigned"
    }
  }

  custom_data = base64encode(templatefile(
    var.use_phase1_cloud_init ? "${path.module}/cloud-init-phase1.yaml" : "${path.module}/cloud-init.yaml",
    {
      node_type        = var.node_type
      node_index       = 0
      cluster_name     = var.cluster_name
      key_vault_id     = var.key_vault_id
      genesis_file_path = var.genesis_file_path
      admin_username   = var.admin_username
    }
  ))

  upgrade_mode = "Manual"

  tags = merge(var.tags, {
    NodeType = var.node_type
  })
}

# Outputs are defined in outputs.tf

