# Regional Landing Zone Module
# Deploys a complete landing zone for a single Azure region
# Follows Cloud for Sovereignty and Well-Architected Framework principles

variable "region" {
  description = "Azure region (e.g., westeurope, northeurope)"
  type        = string
  validation {
    condition = contains([
      "westeurope",
      "northeurope",
      "uksouth",
      "switzerlandnorth",
      "norwayeast",
      "francecentral",
      "germanywestcentral"
    ], var.region)
    error_message = "Region must be a non-US commercial Azure region."
  }
}

variable "environment" {
  description = "Environment name (dev, stage, prod)"
  type        = string
  validation {
    condition     = contains(["dev", "stage", "prod"], var.environment)
    error_message = "Environment must be dev, stage, or prod."
  }
}

variable "management_group_id" {
  description = "Management group ID for this landing zone"
  type        = string
}

variable "hub_vnet_address_space" {
  description = "Address space for hub VNet"
  type        = string
  default     = "10.0.0.0/16"
}

variable "spoke_vnet_address_space" {
  description = "Address space for spoke VNet"
  type        = string
  default     = "10.1.0.0/16"
}

variable "tags" {
  description = "Tags to apply to all resources"
  type        = map(string)
  default     = {}
}

# Local values for naming
locals {
  region_abbrev = {
    westeurope         = "we"
    northeurope        = "ne"
    uksouth            = "uk"
    switzerlandnorth   = "ch"
    norwayeast         = "no"
    francecentral      = "fr"
    germanywestcentral = "de"
  }

  env_abbrev = {
    dev   = "dev"
    stage = "stg"
    prod  = "prd"
  }

  region_short = lookup(local.region_abbrev, var.region, "we")
  env_short    = lookup(local.env_abbrev, var.environment, "dev")
  name_prefix  = "az-${local.region_short}"

  common_tags = merge(var.tags, {
    Region           = var.region
    Environment      = var.environment
    DataResidency    = var.region
    ManagedBy        = "terraform"
    LandingZone      = "regional"
    SovereigntyLevel = "high"
  })
}

# Resource Group
resource "azurerm_resource_group" "landing_zone" {
  name     = "${local.name_prefix}-rg-${local.env_short}-lz"
  location = var.region

  tags = local.common_tags
}

# Hub Virtual Network
resource "azurerm_virtual_network" "hub" {
  name                = "${local.name_prefix}-vnet-${local.env_short}-hub"
  address_space       = [var.hub_vnet_address_space]
  location            = var.region
  resource_group_name = azurerm_resource_group.landing_zone.name

  tags = merge(local.common_tags, {
    Purpose = "HubNetwork"
  })
}

# Hub Subnets
resource "azurerm_subnet" "hub_gateway" {
  name                 = "GatewaySubnet"
  resource_group_name  = azurerm_resource_group.landing_zone.name
  virtual_network_name = azurerm_virtual_network.hub.name
  address_prefixes     = [cidrsubnet(var.hub_vnet_address_space, 8, 0)]
}

resource "azurerm_subnet" "hub_firewall" {
  name                 = "AzureFirewallSubnet"
  resource_group_name  = azurerm_resource_group.landing_zone.name
  virtual_network_name = azurerm_virtual_network.hub.name
  address_prefixes     = [cidrsubnet(var.hub_vnet_address_space, 8, 1)]
}

resource "azurerm_subnet" "hub_management" {
  name                 = "ManagementSubnet"
  resource_group_name  = azurerm_resource_group.landing_zone.name
  virtual_network_name = azurerm_virtual_network.hub.name
  address_prefixes     = [cidrsubnet(var.hub_vnet_address_space, 8, 2)]
}

# Azure Firewall
resource "azurerm_public_ip" "firewall" {
  name                = "${local.name_prefix}-pip-${local.env_short}-fw"
  location            = var.region
  resource_group_name = azurerm_resource_group.landing_zone.name
  allocation_method   = "Static"
  sku                 = "Standard"

  tags = local.common_tags
}

resource "azurerm_firewall" "hub" {
  name                = "${local.name_prefix}-fw-${local.env_short}-hub"
  location            = var.region
  resource_group_name = azurerm_resource_group.landing_zone.name
  sku_name            = "AZFW_VNet"
  sku_tier            = "Standard"

  ip_configuration {
    name                 = "configuration"
    subnet_id            = azurerm_subnet.hub_firewall.id
    public_ip_address_id = azurerm_public_ip.firewall.id
  }

  tags = local.common_tags
}

# Spoke Virtual Network
resource "azurerm_virtual_network" "spoke" {
  name                = "${local.name_prefix}-vnet-${local.env_short}-spoke"
  address_space       = [var.spoke_vnet_address_space]
  location            = var.region
  resource_group_name = azurerm_resource_group.landing_zone.name

  tags = merge(local.common_tags, {
    Purpose = "SpokeNetwork"
  })
}

# Spoke Subnets
resource "azurerm_subnet" "spoke_app" {
  name                 = "ApplicationSubnet"
  resource_group_name  = azurerm_resource_group.landing_zone.name
  virtual_network_name = azurerm_virtual_network.spoke.name
  address_prefixes     = [cidrsubnet(var.spoke_vnet_address_space, 8, 0)]
}

resource "azurerm_subnet" "spoke_db" {
  name                 = "DatabaseSubnet"
  resource_group_name  = azurerm_resource_group.landing_zone.name
  virtual_network_name = azurerm_virtual_network.spoke.name
  address_prefixes     = [cidrsubnet(var.spoke_vnet_address_space, 8, 1)]
  
  delegation {
    name = "postgresql-delegation"
    service_delegation {
      name = "Microsoft.DBforPostgreSQL/flexibleServers"
      actions = [
        "Microsoft.Network/virtualNetworks/subnets/join/action",
      ]
    }
  }
}

resource "azurerm_subnet" "spoke_storage" {
  name                 = "StorageSubnet"
  resource_group_name  = azurerm_resource_group.landing_zone.name
  virtual_network_name = azurerm_virtual_network.spoke.name
  address_prefixes     = [cidrsubnet(var.spoke_vnet_address_space, 8, 2)]
}

# VNet Peering: Hub to Spoke
resource "azurerm_virtual_network_peering" "hub_to_spoke" {
  name                      = "hub-to-spoke"
  resource_group_name       = azurerm_resource_group.landing_zone.name
  virtual_network_name      = azurerm_virtual_network.hub.name
  remote_virtual_network_id = azurerm_virtual_network.spoke.id
  allow_forwarded_traffic   = true
  allow_gateway_transit     = true
}

resource "azurerm_virtual_network_peering" "spoke_to_hub" {
  name                      = "spoke-to-hub"
  resource_group_name       = azurerm_resource_group.landing_zone.name
  virtual_network_name      = azurerm_virtual_network.spoke.name
  remote_virtual_network_id = azurerm_virtual_network.hub.id
  allow_forwarded_traffic   = true
  use_remote_gateways       = false
}

# Data source for current client config
data "azurerm_client_config" "current" {}

# Key Vault (Regional)
resource "azurerm_key_vault" "regional" {
  name                = "${local.name_prefix}-kv-${local.env_short}-${local.region_short}"
  location            = var.region
  resource_group_name = azurerm_resource_group.landing_zone.name
  tenant_id           = data.azurerm_client_config.current.tenant_id
  sku_name            = "premium"

  # Network ACLs - Private endpoint only
  network_acls {
    default_action = "Deny"
    bypass         = "AzureServices"
  }

  # Enable soft delete and purge protection
  soft_delete_retention_days = 90
  purge_protection_enabled   = var.environment == "prod"

  tags = merge(local.common_tags, {
    Purpose = "RegionalSecrets"
  })
}

# Private Endpoint for Key Vault
resource "azurerm_private_endpoint" "key_vault" {
  name                = "${local.name_prefix}-pe-${local.env_short}-kv"
  location            = var.region
  resource_group_name = azurerm_resource_group.landing_zone.name
  subnet_id           = azurerm_subnet.hub_management.id

  private_service_connection {
    name                           = "kv-connection"
    private_connection_resource_id = azurerm_key_vault.regional.id
    subresource_names              = ["vault"]
    is_manual_connection           = false
  }

  tags = local.common_tags
}

# Log Analytics Workspace (Regional)
resource "azurerm_log_analytics_workspace" "regional" {
  name                = "${local.name_prefix}-law-${local.env_short}-${local.region_short}"
  location            = var.region
  resource_group_name = azurerm_resource_group.landing_zone.name
  sku                 = "PerGB2018"
  retention_in_days   = var.environment == "prod" ? 90 : 30

  tags = merge(local.common_tags, {
    Purpose = "RegionalLogging"
  })
}

# Storage Account (Regional)
resource "azurerm_storage_account" "regional" {
  name                     = "${local.name_prefix}sa${local.env_short}${local.region_short}"
  resource_group_name      = azurerm_resource_group.landing_zone.name
  location                 = var.region
  account_tier             = "Standard"
  account_replication_type = var.environment == "prod" ? "GRS" : "LRS"
  min_tls_version          = "TLS1_2"
  allow_blob_public_access = false

  # Customer-managed encryption
  identity {
    type = "SystemAssigned"
  }

  blob_properties {
    versioning_enabled = true
    delete_retention_policy {
      days = var.environment == "prod" ? 90 : 30
    }
  }

  tags = merge(local.common_tags, {
    Purpose = "RegionalStorage"
  })
}

# Private Endpoint for Storage Account
resource "azurerm_private_endpoint" "storage" {
  name                = "${local.name_prefix}-pe-${local.env_short}-st"
  location            = var.region
  resource_group_name = azurerm_resource_group.landing_zone.name
  subnet_id           = azurerm_subnet.spoke_storage.id

  private_service_connection {
    name                           = "storage-connection"
    private_connection_resource_id = azurerm_storage_account.regional.id
    subresource_names              = ["blob"]
    is_manual_connection           = false
  }

  tags = local.common_tags
}

# Outputs
output "resource_group_name" {
  value = azurerm_resource_group.landing_zone.name
}

output "hub_vnet_id" {
  value = azurerm_virtual_network.hub.id
}

output "spoke_vnet_id" {
  value = azurerm_virtual_network.spoke.id
}

output "key_vault_id" {
  value = azurerm_key_vault.regional.id
}

output "log_analytics_workspace_id" {
  value = azurerm_log_analytics_workspace.regional.workspace_id
}

output "storage_account_name" {
  value = azurerm_storage_account.regional.name
}

