data "kubernetes_service_v1" "ngx-write" {
  depends_on = [module.cloud-addon-cd]

  metadata {
    name      = "ingress-nginx-write-controller-internal"
    namespace = "kube-system"
  }

  lifecycle {
    postcondition {
      condition     = self.metadata.0.labels == null || try(self.metadata.0.labels["service.k8s.alibaba/loadbalancer-id"], "") != ""
      error_message = "can't get resource id for ingress-nginx-write-controller-internal"
    }
  }
}

# Tracks the values that, when changed, should cause the ROS stack to be fully
# replaced. This is necessary because `replace_triggered_by` in a lifecycle block
# can only reference resource attributes — not locals or variables directly.
# Wrapping them in a terraform_data resource provides a stable reference point.
resource "terraform_data" "privatelink_triggers" {
  input = {
    cluster_name = local.cluster_name
    zone_ids     = var.zone_ids
    resource_id  = try(data.kubernetes_service_v1.ngx-write.metadata.0.labels["service.k8s.alibaba/loadbalancer-id"], "")
  }
}

resource "alicloud_ros_stack" "privatelink_service" {
  stack_name    = "auto-deploy-${local.cluster_name}-privatelink-service"
  template_body = file("${path.module}/privatelink-alicloud-tmpl.json")

  parameters {
    parameter_key   = "Name"
    parameter_value = "${local.cluster_name}-privatelink-service"
  }

  parameters {
    parameter_key = "Resources"
    parameter_value = jsonencode([
      for zone_id in var.zone_ids : {
        ZoneId       = zone_id
        ResourceId   = try(data.kubernetes_service_v1.ngx-write.metadata.0.labels["service.k8s.alibaba/loadbalancer-id"], "")
        ResourceType = "nlb"
      }
    ])
  }

  # Ignore all changes to the `parameters` blocks after initial creation.
  #
  # Background: The alicloud provider stores `parameters` as a TypeSet internally.
  # The hash function used to identify set members produces different values for the
  # same parameter depending on whether the value was returned by the remote API (read)
  # or computed locally from the config. This causes Terraform to perceive the
  # "Resources" parameter as deleted-and-recreated on every plan, even when the
  # actual JSON content is byte-for-byte identical.
  #
  # Additionally, the AliCloud ROS API explicitly rejects no-op updates with:
  #   code: 400 NotSupported — "Update the completely same stack is not supported."
  # meaning even if Terraform attempts the update, it will always fail.
  #
  # To work around both issues, parameters are fully ignored for drift detection.
  # Instead, intentional changes to local.cluster_name or var.zone_ids are handled
  # via replace_triggered_by (see terraform_data.privatelink_triggers above):
  # when those values change, the entire stack is destroyed and recreated with the
  # updated parameters, bypassing the broken in-place update path entirely.
  lifecycle {
    ignore_changes = [parameters]

    # Force full replacement (destroy + create) whenever local.cluster_name or
    # var.zone_ids change. This is the only reliable way to propagate parameter
    # updates given the alicloud provider's TypeSet hashing bug and the ROS API's
    # rejection of no-op in-place updates.
    replace_triggered_by = [terraform_data.privatelink_triggers]
  }
}
