data "aws_s3_object" "region_state" {
  bucket = "autonomous-deployment-terraform-state"
  key    = "aws/region/${var.env}-${var.aws_region}.json"

  provider = aws.tf_state
}

locals {
  region_outputs          = jsondecode(data.aws_s3_object.region_state.body).outputs
  rds_password_secret_arn = local.region_outputs.password_secret_arn.value
  rds_publicly_accessible = local.region_outputs.publicly_accessible.value
  rds_endpoint            = local.region_outputs.endpoint.value
  rds_rcfg_arn            = try(local.region_outputs.rcfg_arn.value, null)
  rds_proxy_name          = try(local.region_outputs.proxy_name.value, null)
  rds_proxy_service       = try(local.region_outputs.proxy_service.value, null)
  rds_sg_id               = local.region_outputs.rds_sg_id.value
}

data "aws_secretsmanager_secret_version" "rds_password" {
  secret_id = local.rds_password_secret_arn
}

locals {
  rds_secret_string       = data.aws_secretsmanager_secret_version.rds_password.secret_string
  rds_admin_user          = jsondecode(local.rds_secret_string).username
  rds_admin_pass          = jsondecode(local.rds_secret_string).password
  rds_privatelink_enabled = !local.rds_publicly_accessible && (local.rds_rcfg_arn != null || local.rds_proxy_service != null)
  rds_resolved_endpoint   = local.rds_proxy_service != null ? aws_vpc_endpoint.rds[0].dns_entry[0].dns_name : local.rds_endpoint
}

resource "aws_vpc_security_group_ingress_rule" "eks_to_rds" {
  # single_nat_gateway = true in vpc.tf, so there is always exactly 1 NAT public IP.
  # Cannot use for_each/count derived from nat_public_ips because the IP value is
  # unknown at plan time on a fresh apply.

  security_group_id = local.rds_sg_id
  cidr_ipv4         = "${local.eks.public_ips[0]}/32"
  from_port         = 3306
  to_port           = 3306
  ip_protocol       = "tcp"

  tags = {
    Name = "${local.name}-eks-to-rds"
  }
}

resource "aws_security_group" "rds_privatelink" {
  count = local.rds_privatelink_enabled ? 1 : 0

  name        = "${local.name}-rds-privatelink"
  description = "Security group for RDS private endpoint"
  vpc_id      = module.vpc.vpc_id
  egress      = []

  ingress {
    from_port   = 3306
    to_port     = 3306
    protocol    = "tcp"
    cidr_blocks = [module.vpc.vpc_cidr_block]
  }

  tags = {
    Name                        = "${local.name}-rds-privatelink"
    tidbcloud-auto-deploy-owner = local.eks.name
  }
}

resource "aws_vpc_endpoint" "rds" {
  count = local.rds_privatelink_enabled ? 1 : 0

  vpc_id             = module.vpc.vpc_id
  subnet_ids         = module.vpc.private_subnets
  security_group_ids = [aws_security_group.rds_privatelink[0].id]

  vpc_endpoint_type          = local.rds_rcfg_arn != null ? "Resource" : "Interface"
  private_dns_enabled        = local.rds_rcfg_arn != null
  resource_configuration_arn = local.rds_rcfg_arn
  service_name               = local.rds_proxy_service

  tags = {
    Name                        = "${local.name}-rds-privatelink"
    tidbcloud-auto-deploy-owner = local.eks.name
  }
}

module "rds_db_cluster_service" {
  depends_on = [module.vpc, aws_vpc_security_group_ingress_rule.eks_to_rds, aws_vpc_endpoint.rds]
  source     = "../../aws_modules/rds-db"

  kubeconfig_path     = module.kubeconfig.path
  admin_user          = local.rds_admin_user
  admin_pass          = local.rds_admin_pass
  endpoint            = local.rds_resolved_endpoint
  service_name        = "cluster-service"
  logical_region_name = var.logical_region_name
  env                 = var.env
}

module "rds_db_config_center" {
  depends_on = [module.vpc, aws_vpc_security_group_ingress_rule.eks_to_rds, aws_vpc_endpoint.rds]
  source     = "../../aws_modules/rds-db"

  kubeconfig_path     = module.kubeconfig.path
  admin_user          = local.rds_admin_user
  admin_pass          = local.rds_admin_pass
  endpoint            = local.rds_resolved_endpoint
  service_name        = "config-center"
  logical_region_name = var.logical_region_name
  env                 = var.env
}

resource "null_resource" "rds_proxy_auth" {
  count = local.rds_proxy_name != null ? 1 : 0

  depends_on = [
    module.rds_db_cluster_service,
    module.rds_db_config_center,
  ]

  triggers = {
    aws_profile                = local.seed_account
    aws_region                 = var.aws_region
    proxy_name                 = local.rds_proxy_name
    cluster_name               = local.eks.name
    cluster_service_secret_arn = module.rds_db_cluster_service.password_secret_arn
    config_center_secret_arn   = module.rds_db_config_center.password_secret_arn
  }

  provisioner "local-exec" {
    when        = create
    interpreter = ["uv", "run", "-w", "boto3", "python", "-c"]
    environment = {
      AWS_PROFILE                = self.triggers.aws_profile
      AWS_DEFAULT_REGION         = self.triggers.aws_region
      PROXY_NAME                 = self.triggers.proxy_name
      CLUSTER_SERVICE_SECRET_ARN = self.triggers.cluster_service_secret_arn
      CONFIG_CENTER_SECRET_ARN   = self.triggers.config_center_secret_arn
    }
    command = <<-EOT
      import os
      import boto3

      client = boto3.client("rds")

      proxy_name = os.environ["PROXY_NAME"]
      new_secret_arns = [
          os.environ["CLUSTER_SERVICE_SECRET_ARN"],
          os.environ["CONFIG_CENTER_SECRET_ARN"],
      ]

      auth = client.describe_db_proxies(DBProxyName=proxy_name)["DBProxies"][0].get("Auth", [])
      current_secret_arns = {
          entry["SecretArn"]
          for entry in auth
          if entry.get("SecretArn")
      }

      merged_auth = list(auth)
      updated = False

      for secret_arn in new_secret_arns:
          if secret_arn in current_secret_arns:
              print(f"Secret already exists: {secret_arn}")
              continue

          merged_auth.append({
              "AuthScheme": "SECRETS",
              "SecretArn": secret_arn,
              "IAMAuth": "DISABLED",
              "ClientPasswordAuthType": "MYSQL_NATIVE_PASSWORD",
          })
          updated = True
          print(f"Adding new secret: {secret_arn}")

      if updated:
          client.modify_db_proxy(
              DBProxyName=proxy_name,
              Auth=merged_auth,
          )
          print(f"Updated proxy auth for {proxy_name}")
      else:
          print(f"No changes needed for proxy {proxy_name}")
    EOT
  }
}
