locals {
  zone_switch_pairs = zipmap(module.ack.pod_switch_zone_ids, module.ack.pod_switch_ids)
  domain_name       = "${var.env}.aliyun.tidbcloud.com"
  host_record       = "${var.logical_region_name}.regional-api"
  kong_gateway_allowed_cidrs = merge({
    for cidr in formatlist("%s/32", local.base_outputs.public_ips.value) : cidr => "global controlplane"
    }, {
    for cidr in formatlist("%s/32", local.devops_outputs.public_ips.value) : cidr => "bastion"
  })
}

resource "alicloud_security_group_rule" "http" {
  for_each = local.kong_gateway_allowed_cidrs

  type              = "ingress"
  ip_protocol       = "tcp"
  policy            = "accept"
  port_range        = "80/80"
  priority          = 1
  security_group_id = module.ack.security_group_id

  cidr_ip     = each.key
  description = "HTTP | ${each.value}"
}

resource "alicloud_security_group_rule" "https" {
  for_each = local.kong_gateway_allowed_cidrs

  type              = "ingress"
  ip_protocol       = "tcp"
  policy            = "accept"
  port_range        = "443/443"
  priority          = 1
  security_group_id = module.ack.security_group_id

  cidr_ip     = each.key
  description = "HTTPS | ${each.value}"
}

resource "alicloud_security_group_rule" "icmp_all" {
  type              = "ingress"
  ip_protocol       = "icmp"
  policy            = "accept"
  port_range        = "-1/-1"
  priority          = 1
  security_group_id = module.ack.security_group_id
  cidr_ip           = "0.0.0.0/0"

  description = "Allow all ICMP (ping, traceroute)"
}

# Defense-in-depth: drop everything else from 0.0.0.0/0.
# Higher priority number (lower precedence) than the explicit accept rules
# above, so bastion + global controlplane HTTP/HTTPS and ICMP keep working
# while any other source hits this drop rule.
resource "alicloud_security_group_rule" "deny_all_ingress" {
  type              = "ingress"
  ip_protocol       = "all"
  policy            = "drop"
  port_range        = "-1/-1"
  priority          = 100
  security_group_id = module.ack.security_group_id
  cidr_ip           = "0.0.0.0/0"

  description = "Default deny ingress from 0.0.0.0/0"
}

module "gateway-crds" {
  depends_on = [module.cert-manager]
  source     = "../../modules/app"

  kubeconfig_path = module.kubeconfig.path
  workflow        = "deploy-new-region-next-gen-gateway-crds.yaml"
  parameters = {
    env               = var.env
    cloud             = "alicloud"
    region            = var.cloud_region
    cluster           = local.cluster_name
    logicalRegionName = var.logical_region_name
    dnsName           = "${local.host_record}.${local.domain_name}"
  }
  services = [
    {
      name      = "Certificate/regional-api"
      namespace = "kong"
      wait_for  = "condition=Ready"
    },
    {
      name      = "Gateway/kong"
      namespace = "kong"
    }
  ]
}

module "kong-ingress-controller" {
  depends_on = [module.gateway-crds]
  source     = "../../modules/app"

  kubeconfig_path = module.kubeconfig.path
  workflow        = "deploy-new-region-next-gen-kong-ingress-controller.yaml"
  parameters = {
    env               = var.env
    cloud             = "alicloud"
    region            = var.cloud_region
    cluster           = local.cluster_name
    logicalRegionName = var.logical_region_name
    additionalArgs = jsonencode({
      imageRegistry           = local.image_registry
      regionalControlplaneIPs = formatlist("%s/32", module.ack.public_ips)
      globalControlplaneIPs   = formatlist("%s/32", local.base_outputs.public_ips.value)
      zoneMaps                = join(",", [for key, value in local.zone_switch_pairs : "${key}:${value}"])
      securityGroupIds        = module.ack.security_group_id
    })
  }
  services = [
    {
      name      = "deploy/kong-kong"
      namespace = "kong"
      wait_for  = "jsonpath='{.status.availableReplicas}'=REPLICAS"
    },
    {
      name      = "service/kong-kong-proxy"
      namespace = "kong"
      wait_for  = "jsonpath='{.status.loadBalancer.ingress}'"
    }
  ]
}

data "kubernetes_service_v1" "kong_svc" {
  depends_on = [module.kong-ingress-controller]

  metadata {
    name      = "kong-kong-proxy"
    namespace = "kong"
  }

  lifecycle {
    postcondition {
      condition     = self.status == null || can(self.status.0.load_balancer.0.ingress.0.hostname)
      error_message = "can't get hostname for kong-kong-proxy"
    }
  }
}

resource "alicloud_alidns_record" "kong-gateway-dns" {
  depends_on  = [module.kong-ingress-controller]
  domain_name = local.domain_name
  rr          = local.host_record
  type        = "CNAME"
  value       = try(data.kubernetes_service_v1.kong_svc.status.0.load_balancer.0.ingress.0.hostname, "")
}