terraform {
  required_providers {
    alicloud = {
      source  = "aliyun/alicloud"
      version = "1.266.0"
    }
  }

  backend "oss" {
    profile = "default"
  }
}

provider "alicloud" {
  profile = "default"
  region  = var.region
}

data "alicloud_db_instances" "this" {
  name_regex = var.rds_instance_name

  tags = {
    environment = var.env
    usedby      = "dbaas-control-plane-seed"
    servicetype = "nextgen"
    tenant      = "admin"
  }
}

resource "alicloud_rds_whitelist_template" "this" {
  ip_white_list = var.k8s_public_ips
  template_name = var.k8s_name
}

resource "null_resource" "alicloud_db_whitelist_template_attachment" {
  triggers = {
    instance_id = data.alicloud_db_instances.this.ids.0
    template_id = alicloud_rds_whitelist_template.this.id
  }

  provisioner "local-exec" {
    command = "aliyun rds AttachWhitelistTemplateToInstance --InsName ${self.triggers.instance_id} --TemplateId ${self.triggers.template_id}"
    when    = create
  }

  provisioner "local-exec" {
    command = "aliyun rds DetachWhitelistTemplateToInstance --InsName ${self.triggers.instance_id} --TemplateId ${self.triggers.template_id}"
    when    = destroy
  }
}

resource "random_password" "cluster_service" {
  length           = 16
  special          = true
  override_special = "!@#$%^&*()_+-="
}

resource "random_password" "config_center" {
  length           = 16
  special          = true
  override_special = "!@#$%^&*()_+-="
}

resource "alicloud_rds_account" "cluster_service" {
  db_instance_id   = data.alicloud_db_instances.this.ids.0
  account_name     = "${var.db_user_prefix}_cluster_service"
  account_password = random_password.cluster_service.result
}

resource "alicloud_rds_account" "config_center" {
  db_instance_id   = data.alicloud_db_instances.this.ids.0
  account_name     = "${var.db_user_prefix}_config_center"
  account_password = random_password.config_center.result
}

data "alicloud_kms_keys" "this" {
  description_regex = "${var.rds_instance_name}-kms-default-key"
}

data "alicloud_kms_instances" "this" {
  instance_name = "${var.rds_instance_name}-kms"
}

resource "alicloud_kms_secret" "cluster_service" {
  depends_on  = [alicloud_rds_account.cluster_service]
  secret_name = "${var.db_pass_secret_name_prefix}_cluster_service"
  secret_data = jsonencode({
    username = "${var.db_user_prefix}_cluster_service"
    password = random_password.cluster_service.result
  })
  version_id        = "v1"
  description       = "RDS password for ${var.db_user_prefix}_cluster_service"
  encryption_key_id = data.alicloud_kms_keys.this.ids.0
  dkms_instance_id  = data.alicloud_kms_instances.this.ids.0

  lifecycle {
    precondition {
      condition     = length(data.alicloud_kms_keys.this.ids) == 1
      error_message = "expect exactly one kms key, found ${length(data.alicloud_kms_keys.this.ids)}"
    }

    precondition {
      condition     = length(data.alicloud_kms_instances.this.ids) == 1
      error_message = "expect exactly one kms instance, found ${length(data.alicloud_kms_instances.this.ids)}"
    }
  }
}

resource "alicloud_kms_secret" "config_center" {
  depends_on  = [alicloud_rds_account.config_center]
  secret_name = "${var.db_pass_secret_name_prefix}_config_center"
  secret_data = jsonencode({
    username = "${var.db_user_prefix}_config_center"
    password = random_password.config_center.result
  })
  version_id        = "v1"
  description       = "RDS password for ${var.db_user_prefix}_config_center"
  encryption_key_id = data.alicloud_kms_keys.this.ids.0
  dkms_instance_id  = data.alicloud_kms_instances.this.ids.0

  lifecycle {
    precondition {
      condition     = length(data.alicloud_kms_keys.this.ids) == 1
      error_message = "expect exactly one kms key, found ${length(data.alicloud_kms_keys.this.ids)}"
    }

    precondition {
      condition     = length(data.alicloud_kms_instances.this.ids) == 1
      error_message = "expect exactly one kms instance, found ${length(data.alicloud_kms_instances.this.ids)}"
    }
  }
}

resource "alicloud_db_database" "cluster_service" {
  instance_id = data.alicloud_db_instances.this.ids.0
  name        = "${var.db_name_prefix}_cluster_service"

  lifecycle {
    precondition {
      condition     = length(data.alicloud_db_instances.this.ids) == 1
      error_message = "expect exactly one db instance, found ${length(data.alicloud_db_instances.this.ids)}"
    }
  }
}

resource "alicloud_db_database" "config_center" {
  instance_id = data.alicloud_db_instances.this.ids.0
  name        = "${var.db_name_prefix}_config_center"

  lifecycle {
    precondition {
      condition     = length(data.alicloud_db_instances.this.ids) == 1
      error_message = "expect exactly one db instance, found ${length(data.alicloud_db_instances.this.ids)}"
    }
  }
}

resource "alicloud_db_account_privilege" "cluster_service" {
  instance_id  = data.alicloud_db_instances.this.ids.0
  account_name = alicloud_rds_account.cluster_service.account_name
  db_names     = [alicloud_db_database.cluster_service.name]
  privilege    = "ReadWrite"

  lifecycle {
    precondition {
      condition     = length(data.alicloud_db_instances.this.ids) == 1
      error_message = "expect exactly one db instance, found ${length(data.alicloud_db_instances.this.ids)}"
    }
  }
}

resource "alicloud_db_account_privilege" "config_center" {
  instance_id  = data.alicloud_db_instances.this.ids.0
  account_name = alicloud_rds_account.config_center.account_name
  db_names     = [alicloud_db_database.config_center.name]
  privilege    = "ReadWrite"

  lifecycle {
    precondition {
      condition     = length(data.alicloud_db_instances.this.ids) == 1
      error_message = "expect exactly one db instance, found ${length(data.alicloud_db_instances.this.ids)}"
    }
  }
}

data "external" "rds_public_address" {
  program = ["bash", "-c", <<-EOT
    aliyun rds DescribeDBInstanceNetInfo --DBInstanceId ${data.alicloud_db_instances.this.ids.0} | \
    jq '
      {
        public_connection_string: .DBInstanceNetInfos.DBInstanceNetInfo
        | map(select(.IPType == "Public").ConnectionString)
        | first
      }
    '
    EOT
  ]
}

resource "null_resource" "rds_public_address_validation" {
  lifecycle {
    precondition {
      condition     = length(data.external.rds_public_address.result.public_connection_string) > 0
      error_message = "RDS instance ${data.alicloud_db_instances.this.ids.0} has no public address"
    }
  }
}

output "cluster_service" {
  value = {
    host                 = data.external.rds_public_address.result.public_connection_string
    port                 = tonumber(data.alicloud_db_instances.this.instances.0.port)
    db                   = alicloud_db_database.cluster_service.name
    username             = alicloud_rds_account.cluster_service.account_name
    password_secret_name = alicloud_kms_secret.cluster_service.secret_name
    kms_instance_id      = data.alicloud_kms_instances.this.ids.0
  }
}

output "config_center" {
  value = {
    host                 = data.external.rds_public_address.result.public_connection_string
    port                 = tonumber(data.alicloud_db_instances.this.instances.0.port)
    db                   = alicloud_db_database.config_center.name
    username             = alicloud_rds_account.config_center.account_name
    password_secret_name = alicloud_kms_secret.config_center.secret_name
    kms_instance_id      = data.alicloud_kms_instances.this.ids.0
  }
}