###############################################################################
# Networking Module — Main
# Deploys: Resource Groups, VNets, Subnets, NSGs, NAT Gateway, Peerings
###############################################################################

locals {
  prefix = "${var.project}-${var.environment}"
}

# =============================================================================
# Resource Groups (D1 Task 2)
# =============================================================================

resource "azurerm_resource_group" "network" {
  name     = "rg-${local.prefix}-network"
  location = var.location
  tags     = var.tags
}

resource "azurerm_resource_group" "databricks" {
  name     = "rg-${local.prefix}-databricks"
  location = var.location
  tags     = var.tags
}

resource "azurerm_resource_group" "storage" {
  name     = "rg-${local.prefix}-storage"
  location = var.location
  tags     = var.tags
}

resource "azurerm_resource_group" "governance" {
  name     = "rg-${local.prefix}-governance"
  location = var.location
  tags     = var.tags
}

resource "azurerm_resource_group" "keyvault" {
  name     = "rg-${local.prefix}-keyvault"
  location = var.location
  tags     = var.tags
}

resource "azurerm_resource_group" "monitoring" {
  name     = "rg-${local.prefix}-monitoring"
  location = var.location
  tags     = var.tags
}

# =============================================================================
# Main MDP VNet (D1 Task 3)
# =============================================================================

resource "azurerm_virtual_network" "main" {
  name                = "vnet-${local.prefix}"
  location            = var.location
  resource_group_name = azurerm_resource_group.network.name
  address_space       = [var.vnet_cidr]
  tags                = var.tags
}

# --- Databricks Host Subnet ---
resource "azurerm_subnet" "dbx_host" {
  name                 = "snet-${local.prefix}-dbx-host"
  resource_group_name  = azurerm_resource_group.network.name
  virtual_network_name = azurerm_virtual_network.main.name
  address_prefixes     = [var.dbx_host_subnet_cidr]

  delegation {
    name = "databricks-host"
    service_delegation {
      name = "Microsoft.Databricks/workspaces"
      actions = [
        "Microsoft.Network/virtualNetworks/subnets/join/action",
        "Microsoft.Network/virtualNetworks/subnets/prepareNetworkPolicies/action",
        "Microsoft.Network/virtualNetworks/subnets/unprepareNetworkPolicies/action",
      ]
    }
  }
}

# --- Databricks Container Subnet ---
resource "azurerm_subnet" "dbx_container" {
  name                 = "snet-${local.prefix}-dbx-container"
  resource_group_name  = azurerm_resource_group.network.name
  virtual_network_name = azurerm_virtual_network.main.name
  address_prefixes     = [var.dbx_container_subnet_cidr]

  delegation {
    name = "databricks-container"
    service_delegation {
      name = "Microsoft.Databricks/workspaces"
      actions = [
        "Microsoft.Network/virtualNetworks/subnets/join/action",
        "Microsoft.Network/virtualNetworks/subnets/prepareNetworkPolicies/action",
        "Microsoft.Network/virtualNetworks/subnets/unprepareNetworkPolicies/action",
      ]
    }
  }
}

# --- Private Endpoints Subnet ---
resource "azurerm_subnet" "private_endpoints" {
  name                                      = "snet-${local.prefix}-pe"
  resource_group_name                       = azurerm_resource_group.network.name
  virtual_network_name                      = azurerm_virtual_network.main.name
  address_prefixes                 = [var.private_endpoints_subnet_cidr]
  private_endpoint_network_policies = "Enabled"
}

# =============================================================================
# Transit VNet (Front-End Private Link)
# =============================================================================

resource "azurerm_virtual_network" "transit" {
  name                = "vnet-${local.prefix}-transit"
  location            = var.location
  resource_group_name = azurerm_resource_group.network.name
  address_space       = [var.transit_vnet_cidr]
  tags                = var.tags
}

resource "azurerm_subnet" "transit" {
  name                                      = "snet-${local.prefix}-transit"
  resource_group_name                       = azurerm_resource_group.network.name
  virtual_network_name                      = azurerm_virtual_network.transit.name
  address_prefixes                  = [var.transit_subnet_cidr]
  private_endpoint_network_policies = "Enabled"
}

# =============================================================================
# VNet Peerings
# =============================================================================

# Main VNet <-> Transit VNet
resource "azurerm_virtual_network_peering" "main_to_transit" {
  name                      = "peer-main-to-transit"
  resource_group_name       = azurerm_resource_group.network.name
  virtual_network_name      = azurerm_virtual_network.main.name
  remote_virtual_network_id = azurerm_virtual_network.transit.id
  allow_forwarded_traffic   = true
}

resource "azurerm_virtual_network_peering" "transit_to_main" {
  name                      = "peer-transit-to-main"
  resource_group_name       = azurerm_resource_group.network.name
  virtual_network_name      = azurerm_virtual_network.transit.name
  remote_virtual_network_id = azurerm_virtual_network.main.id
  allow_forwarded_traffic   = true
}

# Main VNet <-> Hub VNet (if provided)
resource "azurerm_virtual_network_peering" "main_to_hub" {
  count                     = var.hub_vnet_id != "" ? 1 : 0
  name                      = "peer-main-to-hub"
  resource_group_name       = azurerm_resource_group.network.name
  virtual_network_name      = azurerm_virtual_network.main.name
  remote_virtual_network_id = var.hub_vnet_id
  allow_forwarded_traffic   = true
  allow_gateway_transit     = false
  use_remote_gateways       = true
}

# =============================================================================
# NAT Gateway (stable egress IPs for Databricks subnets)
# =============================================================================

resource "azurerm_public_ip" "nat" {
  name                = "pip-${local.prefix}-nat"
  location            = var.location
  resource_group_name = azurerm_resource_group.network.name
  allocation_method   = "Static"
  sku                 = "Standard"
  tags                = var.tags
}

resource "azurerm_nat_gateway" "main" {
  name                    = "natgw-${local.prefix}"
  location                = var.location
  resource_group_name     = azurerm_resource_group.network.name
  sku_name                = "Standard"
  idle_timeout_in_minutes = 10
  tags                    = var.tags
}

resource "azurerm_nat_gateway_public_ip_association" "main" {
  nat_gateway_id       = azurerm_nat_gateway.main.id
  public_ip_address_id = azurerm_public_ip.nat.id
}

resource "azurerm_subnet_nat_gateway_association" "dbx_host" {
  subnet_id      = azurerm_subnet.dbx_host.id
  nat_gateway_id = azurerm_nat_gateway.main.id
}

resource "azurerm_subnet_nat_gateway_association" "dbx_container" {
  subnet_id      = azurerm_subnet.dbx_container.id
  nat_gateway_id = azurerm_nat_gateway.main.id
}

# =============================================================================
# NSGs — Databricks Subnets (see Phase 0 plan §3 NSG Rule Set)
# =============================================================================

resource "azurerm_network_security_group" "dbx" {
  name                = "nsg-${local.prefix}-dbx"
  location            = var.location
  resource_group_name = azurerm_resource_group.network.name
  tags                = var.tags

  # --- Inbound ---

  security_rule {
    name                       = "AllowDatabricksControlPlaneInbound"
    priority                   = 100
    direction                  = "Inbound"
    access                     = "Allow"
    protocol                   = "Tcp"
    source_port_range          = "*"
    destination_port_range     = "443"
    source_address_prefix      = "AzureDatabricks"
    destination_address_prefix = "*"
  }

  security_rule {
    name                       = "AllowHostToContainer"
    priority                   = 200
    direction                  = "Inbound"
    access                     = "Allow"
    protocol                   = "*"
    source_port_range          = "*"
    destination_port_range     = "*"
    source_address_prefix      = var.dbx_host_subnet_cidr
    destination_address_prefix = var.dbx_container_subnet_cidr
  }

  security_rule {
    name                       = "AllowContainerToHost"
    priority                   = 201
    direction                  = "Inbound"
    access                     = "Allow"
    protocol                   = "*"
    source_port_range          = "*"
    destination_port_range     = "*"
    source_address_prefix      = var.dbx_container_subnet_cidr
    destination_address_prefix = var.dbx_host_subnet_cidr
  }

  security_rule {
    name                       = "DenyAllInbound"
    priority                   = 4096
    direction                  = "Inbound"
    access                     = "Deny"
    protocol                   = "*"
    source_port_range          = "*"
    destination_port_range     = "*"
    source_address_prefix      = "*"
    destination_address_prefix = "*"
  }

  # --- Outbound ---

  security_rule {
    name                       = "AllowDatabricksControlPlaneOutbound"
    priority                   = 100
    direction                  = "Outbound"
    access                     = "Allow"
    protocol                   = "Tcp"
    source_port_range          = "*"
    destination_port_range     = "443"
    source_address_prefix      = "*"
    destination_address_prefix = "AzureDatabricks"
  }

  security_rule {
    name                       = "AllowSqlOutbound"
    priority                   = 110
    direction                  = "Outbound"
    access                     = "Allow"
    protocol                   = "Tcp"
    source_port_range          = "*"
    destination_port_range     = "3306"
    source_address_prefix      = "*"
    destination_address_prefix = "Sql"
  }

  security_rule {
    name                       = "AllowStorageOutbound"
    priority                   = 120
    direction                  = "Outbound"
    access                     = "Allow"
    protocol                   = "Tcp"
    source_port_range          = "*"
    destination_port_range     = "443"
    source_address_prefix      = "*"
    destination_address_prefix = "Storage"
  }

  security_rule {
    name                       = "AllowEventHubOutbound"
    priority                   = 130
    direction                  = "Outbound"
    access                     = "Allow"
    protocol                   = "Tcp"
    source_port_range          = "*"
    destination_port_range     = "9093"
    source_address_prefix      = "*"
    destination_address_prefix = "EventHub"
  }

  security_rule {
    name                       = "AllowPrivateEndpoints"
    priority                   = 200
    direction                  = "Outbound"
    access                     = "Allow"
    protocol                   = "Tcp"
    source_port_range          = "*"
    destination_port_range     = "443"
    source_address_prefix      = "*"
    destination_address_prefix = var.private_endpoints_subnet_cidr
  }

  security_rule {
    name                       = "DenyInternetOutbound"
    priority                   = 4096
    direction                  = "Outbound"
    access                     = "Deny"
    protocol                   = "*"
    source_port_range          = "*"
    destination_port_range     = "*"
    source_address_prefix      = "*"
    destination_address_prefix = "Internet"
  }
}

# --- Associate NSG to both Databricks subnets ---

resource "azurerm_subnet_network_security_group_association" "dbx_host" {
  subnet_id                 = azurerm_subnet.dbx_host.id
  network_security_group_id = azurerm_network_security_group.dbx.id
}

resource "azurerm_subnet_network_security_group_association" "dbx_container" {
  subnet_id                 = azurerm_subnet.dbx_container.id
  network_security_group_id = azurerm_network_security_group.dbx.id
}

# =============================================================================
# Private DNS Zones
# =============================================================================

resource "azurerm_private_dns_zone" "databricks" {
  name                = "privatelink.azuredatabricks.net"
  resource_group_name = azurerm_resource_group.network.name
  tags                = var.tags
}

resource "azurerm_private_dns_zone" "dfs" {
  name                = "privatelink.dfs.core.windows.net"
  resource_group_name = azurerm_resource_group.network.name
  tags                = var.tags
}

resource "azurerm_private_dns_zone" "vault" {
  name                = "privatelink.vaultcore.azure.net"
  resource_group_name = azurerm_resource_group.network.name
  tags                = var.tags
}

resource "azurerm_private_dns_zone" "purview" {
  name                = "privatelink.purview.azure.com"
  resource_group_name = azurerm_resource_group.network.name
  tags                = var.tags
}

# --- Link DNS zones to VNets ---

resource "azurerm_private_dns_zone_virtual_network_link" "databricks_main" {
  name                  = "link-dbx-main"
  resource_group_name   = azurerm_resource_group.network.name
  private_dns_zone_name = azurerm_private_dns_zone.databricks.name
  virtual_network_id    = azurerm_virtual_network.main.id
}

resource "azurerm_private_dns_zone_virtual_network_link" "databricks_transit" {
  name                  = "link-dbx-transit"
  resource_group_name   = azurerm_resource_group.network.name
  private_dns_zone_name = azurerm_private_dns_zone.databricks.name
  virtual_network_id    = azurerm_virtual_network.transit.id
}

resource "azurerm_private_dns_zone_virtual_network_link" "dfs_main" {
  name                  = "link-dfs-main"
  resource_group_name   = azurerm_resource_group.network.name
  private_dns_zone_name = azurerm_private_dns_zone.dfs.name
  virtual_network_id    = azurerm_virtual_network.main.id
}

resource "azurerm_private_dns_zone_virtual_network_link" "vault_main" {
  name                  = "link-vault-main"
  resource_group_name   = azurerm_resource_group.network.name
  private_dns_zone_name = azurerm_private_dns_zone.vault.name
  virtual_network_id    = azurerm_virtual_network.main.id
}

resource "azurerm_private_dns_zone_virtual_network_link" "purview_main" {
  name                  = "link-purview-main"
  resource_group_name   = azurerm_resource_group.network.name
  private_dns_zone_name = azurerm_private_dns_zone.purview.name
  virtual_network_id    = azurerm_virtual_network.main.id
}
