#!/usr/bin/env bash
set -xueo pipefail

remote_config=${CONFIG_PATH}
local_config=/tmp/base-config.yaml

bucket_name=${remote_config#s3://}
bucket_name=${bucket_name%%/*}
output_bucket_region=$(aws s3api get-bucket-location --bucket=$bucket_name --query="LocationConstraint" \
  --region=us-west-2 --output=text --no-cli-pager)
aws s3 cp "${remote_config}" "${local_config}" --region=$output_bucket_region

argocd_repo=tidbcloud/app-delivery
region=$(yq '.region' "${local_config}")
env=$(yq '.env' "${local_config}")
cloud=$(yq '.cloudProvider' "${local_config}")
cluster=$(yq '.k8s.name' "${local_config}")
jobId=$(yq '.jobId' "${local_config}")
logical_region_name=$(yq '.name' "${local_config}")

publicly_accessible=$(yq '.jobOptions.ng-service.rds.publicly_accessible // "true"' "${local_config}")
rds_port=$(yq '.jobOptions.ng-service.rds.port' "${local_config}")
rds_host=$(yq '.jobOptions.ng-service.rds.host' "${local_config}")
rds_password_secret=$(yq '.jobOptions.ng-service.rds.password_secret_name' "${local_config}")
rcfg_arn=$(yq '.jobOptions.ng-service.rds.rcfg_arn // ""' "${local_config}")
proxy_service=$(yq '.jobOptions.ng-service.rds.proxy_service // ""' "${local_config}")
proxy_name=$(yq '.jobOptions.ng-service.rds.proxy_name // ""' "${local_config}")
resource_owner_tag=$(yq '.jobOptions.resourceOwnerTag' "${local_config}")

if [[ "$publicly_accessible" == "true" ]]; then
  echo "===================== configure rds security group ====================="
  rds_name="${rds_host%%.cluster*}"
  tag_key="rds"
  sg_name1="rds-${rds_name}-sg"
  sg_name2="${rds_name}-sg"
  ips=$(yq -ojson '.k8s.publicIps | map(. + "/32")' "$local_config")

  # 1. Find VPC by RDS tag
  vpc_id=$(aws ec2 describe-vpcs \
    --filters "Name=tag:${tag_key},Values=${rds_name}" \
    --query "Vpcs[0].VpcId" \
    --output text)

  if [[ "$vpc_id" == "None" ]]; then
    echo "❌ VPC not found (tag:${tag_key}=${rds_name})"
    exit 1
  fi
  echo "✅ Found VPC: $vpc_id"

  # 2. Find Security Group by name
  sg_id=$(aws ec2 describe-security-groups \
    --filters "Name=vpc-id,Values=${vpc_id}" "Name=group-name,Values=${sg_name1}" \
    --query "SecurityGroups[0].GroupId" \
    --output text)

  if [[ "$sg_id" == "None" ]]; then
    sg_id=$(aws ec2 describe-security-groups \
    --filters "Name=vpc-id,Values=${vpc_id}" "Name=group-name,Values=${sg_name2}" \
    --query "SecurityGroups[0].GroupId" \
    --output text)
  fi
  if [[ "$sg_id" == "None" ]]; then
    echo "❌ not found Security Group (name:${sg_name1} or name:${sg_name2})"
    exit 1
  fi
  echo "✅ Found Security Group: $sg_id"

  # 3. Check if the IP already exists in the ingress rules
  cirds=$(aws ec2 describe-security-groups \
    --group-ids "$sg_id" \
    --query "SecurityGroups[0].IpPermissions[].IpRanges[].CidrIp" \
    --output json)
  for ip in $(echo "${ips}" | jq -r '.[]'); do
    exists=$(echo "$cirds" | jq "index(\"${ip}\") != null")
    if $exists; then
      echo "ℹ️ Security Group $sg_id contains $ip"
    else
      echo "➕ Insert $ip into $sg_id ingress"
      aws ec2 authorize-security-group-ingress \
        --group-id "$sg_id" \
        --tag-specifications ResourceType=security-group-rule,Tags="[{Key=tidbcloud-auto-deploy-owner,Value=${resource_owner_tag}}]" \
        --ip-permissions '[
          {
            "IpProtocol": "tcp",
            "FromPort": '${rds_port}',
            "ToPort": '${rds_port}',
            "IpRanges": [
              {
                "CidrIp": "'${ip}'",
                "Description": "'${cluster}'"
              }
            ]
          }
        ]'
      echo "✅ Updated ingress rules"
    fi
  done
elif [[ -n "$rcfg_arn" || -n "$proxy_service" ]]; then
  echo "===================== create rds privatelink ====================="
  vpc_id=$(aws eks describe-cluster \
    --name $cluster \
    --query "cluster.resourcesVpcConfig.vpcId" \
    --output text)
  if [[ "$vpc_id" == "None" ]]; then
    echo "❌ VPC not found for cluster $cluster"
    exit 1
  fi
  echo "✅ Found VPC: $vpc_id"

  vpc_cidr=$(aws ec2 describe-vpcs \
    --vpc-ids ${vpc_id} \
    --query 'Vpcs[0].CidrBlock' \
    --output text)
  if [[ "$vpc_cidr" == "None" ]]; then
    echo "❌ VPC CIDR not found for VPC $vpc_id"
    exit 1
  fi
  echo "✅ Found VPC CIDR: $vpc_cidr"

  rds_zones=$(yq '.jobOptions.ng-service.rds.availability_zones' "${local_config}")
  subnets=$(aws ec2 describe-subnets \
    --filters "Name=tag:kubernetes.io/role/internal-elb,Values=*" "Name=vpc-id,Values=${vpc_id}" "Name=availability-zone,Values=${rds_zones}" \
    --query "Subnets[].{SubnetId:SubnetId, Name:Tags[?Key=='Name'].Value}" \
    --output json)
  echo "✅ Found subnets: $subnets"
  subnet_ids=($(echo $subnets | jq -r '.[].SubnetId'))
  echo "✅ Found subnet_ids: ${subnet_ids[@]}"

  sg_name=${cluster}-rds-privatelink
  security_group_id=""
  # create security group for rds privatelink if not exists
  existing_sg=$(aws ec2 describe-security-groups \
    --filters "Name=vpc-id,Values=$vpc_id" "Name=group-name,Values=$sg_name" \
    --query "SecurityGroups[0].GroupId" \
    --output text)
  if [ "$existing_sg" == "None" ]; then
    echo "sg ${sg_name} not found, trying to create one"
    security_group_id=$(aws ec2 create-security-group --vpc-id $vpc_id \
      --group-name $sg_name --description "Security group for rds privatelink" \
      --tag-specifications ResourceType=security-group,Tags="[{Key=Name,Value=$sg_name},{Key=tidbcloud-auto-deploy-owner,Value=${resource_owner_tag}}]" \
      --output text --query 'GroupId')
    echo "✅ sg_id $security_group_id created"

    # Add ingress and egress rules
    aws ec2 authorize-security-group-ingress \
      --group-id $security_group_id \
      --protocol tcp --port ${rds_port} --cidr ${vpc_cidr} \
      --tag-specifications ResourceType=security-group-rule,Tags="[{Key=tidbcloud-auto-deploy-owner,Value=${resource_owner_tag}}]"
    echo "✅ Added ingress rule to $security_group_id for VPC CIDR $vpc_cidr"

    # Del default egress rule
    aws ec2 revoke-security-group-egress \
      --group-id $security_group_id \
      --protocol all \
      --cidr 0.0.0.0/0
    echo "✅ Removed default egress rule from $security_group_id"
  else
    echo "✅ Found existing sg: $existing_sg"
    security_group_id=$existing_sg
  fi

  # create aws private endpoint with endpoint service name if not exists
  # if empty, create it
  endpoint_name=${cluster}-rds-privatelink
  if [[ -n "$rcfg_arn" ]]; then
    existing_endpoint=$(aws ec2 describe-vpc-endpoints \
      --filters "Name=vpc-id,Values=$vpc_id" \
      --query "VpcEndpoints[?ResourceConfigurationArn=='${rcfg_arn}'].VpcEndpointId" \
      --output text)
  elif [[ -n "$proxy_service" ]]; then
    endpoint=$(aws ec2 describe-vpc-endpoints \
      --filters "Name=vpc-id,Values=$vpc_id" "Name=service-name,Values=${proxy_service}" \
      --query "VpcEndpoints[0].{id:VpcEndpointId, dns:DnsEntries[0].DnsName}" \
      --output json)
      existing_endpoint=$(echo $endpoint | jq -r '.id // ""')
      rds_host=$(echo $endpoint | jq -r ".dns // \"$rds_host\"")
  fi
  if [ -z "$existing_endpoint" ]; then
    echo "ℹ️ endpoint $endpoint_name not found, trying to create one"
    if [[ -n "$rcfg_arn" ]]; then
      endpoint_id=$(aws ec2 create-vpc-endpoint \
        --vpc-endpoint-type Resource \
        --vpc-id ${vpc_id} \
        --private-dns-enabled \
        --subnet-ids ${subnet_ids[@]} \
        --security-group-ids ${security_group_id} \
        --tag-specifications ResourceType=vpc-endpoint,Tags="[{Key=Name,Value=$endpoint_name},{Key=tidbcloud-auto-deploy-owner,Value=${resource_owner_tag}}]" \
        --resource-configuration-arn ${rcfg_arn} \
        --query "VpcEndpoint.VpcEndpointId" \
        --output text)
    elif [[ -n "$proxy_service" ]]; then
      endpoint=$(aws ec2 create-vpc-endpoint \
        --vpc-endpoint-type Interface \
        --vpc-id ${vpc_id} \
        --subnet-ids ${subnet_ids[@]} \
        --security-group-ids ${security_group_id} \
        --tag-specifications ResourceType=vpc-endpoint,Tags="[{Key=Name,Value=$endpoint_name},{Key=tidbcloud-auto-deploy-owner,Value=${resource_owner_tag}}]" \
        --service-name ${proxy_service} \
        --query "{id:VpcEndpoint.VpcEndpointId,dns:VpcEndpoint.DnsEntries[0].DnsName}" \
        --output json)
        endpoint_id=$(echo $endpoint | jq -r '.id')
        # we need to use the vpc endpoint dns as rds host
        rds_host=$(echo $endpoint | jq -r '.dns')
        echo "✅ Use rds host $rds_host for private endpoint"
    fi
    echo "✅ endpoint $endpoint_name($endpoint_id) created, waiting for it to become available..."

    max_attempts=30
    sleep=10
    for ((i=0; i<max_attempts; i++)); do
      status=$(aws ec2 describe-vpc-endpoints \
        --vpc-endpoint-ids "$endpoint_id" \
        --query "VpcEndpoints[0].State" \
        --output text)
      echo "Current status: $status"

      if [[ "${status,,}" == "available" ]]; then
        echo "✅ VPC Endpoint is now available!"
        break
      elif [[ "${status,,}" == "failed" ]]; then
        echo "❌ VPC Endpoint creation failed."
        exit 1
      fi
      sleep $sleep
    done
    if [[ "$i" == "$max_attempts" ]]; then
      echo "⏰ Timeout reached after $((max_attempts*sleep)) seconds"
      exit 1
    fi
  fi
  echo "===================== create rds privatelink done ====================="
fi

echo "===================== create rds db ====================="
rds_password_json=$(aws secretsmanager get-secret-value \
  --secret-id ${rds_password_secret} \
  --query "SecretString" \
  --output text)
rds_username=$(echo $rds_password_json | jq -r '.username')
rds_password=$(echo $rds_password_json | jq -r '.password')

echo "Connecting to RDS $rds_host:$rds_port with user $rds_username"
mysql -h "$rds_host" -P "$rds_port" -u "$rds_username" -p"$rds_password" --connect-timeout=5 -e "SELECT 1;"

# helper: get secret value (returns secret string)
get_secret_string() {
  local id="$1"
  if secret_json=$(aws secretsmanager get-secret-value --secret-id "$id" --query SecretString --output text 2>/dev/null); then
    echo "$secret_json"
    return 0
  fi
  return 1
}

# helper: create secret
create_secret() {
  local id="$1"
  local secret_string="$2"
  aws secretsmanager create-secret --name "$id" --secret-string "$secret_string" --tags "Key=tidbcloud-auto-deploy-owner,Value=${resource_owner_tag}" >/dev/null
}

# helper: put secret value (update existing)
put_secret() {
  local id="$1"
  local secret_string="$2"
  aws secretsmanager put-secret-value --secret-id "$id" --secret-string "$secret_string" >/dev/null
}

# generate random password
generate_password() {
  # generate base64
  head -c 256 /dev/urandom | base64 | cut -c1-20 | head -n 1
}

create_or_get_secret() {
  local secret_name=$1
  local db_user=$2
  if secret_json=$(get_secret_string "$secret_name"); then
    echo "Secret exists in Secrets Manager — using existing password ." >&2
    # parse existing secret
    local db_user_in_secret=$(echo "$secret_json" | jq -r '.username // empty')
    local db_pass_in_secret=$(echo "$secret_json" | jq -r '.password // empty')
    if [[ -z "$db_user_in_secret" || -z "$db_pass_in_secret" ]]; then
      echo "❌ Existing secret does not contain username+password keys; aborting." >&2
      exit 1
    fi
    echo "$db_pass_in_secret"
  else
    echo "Secret does not exist — creating new random password and storing in Secrets Manager." >&2
    local password=$(generate_password)
    # store JSON object with username and password
    local secret_payload='{"username":"'"$db_user"'", "password":"'"$password"'"}'
    # Try to create; if already created concurrently, fallback to put
    if create_secret "$secret_name" "$secret_payload"; then
      echo "✅ Created secret $secret_name." >&2
    else
      echo "Create failed (maybe exists concurrently). Attempting to put secret value..." >&2
      put_secret "$secret_name" "$secret_payload" >&2
      echo "✅ Updated secret $secret_name." >&2
    fi
    echo "$password"
  fi
}

create_user_and_db() {
  local db_name=$1
  local username=$2
  local password=$3
  local sql=$(cat <<SQL
CREATE DATABASE IF NOT EXISTS \`$db_name\`;
CREATE USER IF NOT EXISTS '$username'@'%' IDENTIFIED BY '${password}';
ALTER USER '$username'@'%' IDENTIFIED BY '${password}';
GRANT ALL PRIVILEGES ON \`$db_name\`.* TO '$username'@'%';
FLUSH PRIVILEGES;
SQL
)
  mysql -h "$rds_host" -P "$rds_port" -u "$rds_username" -p"$rds_password" -e "$sql"
}

db_logical_region_name=${logical_region_name//-/_}
cluster_service_db="${env}_${db_logical_region_name}_cluster_service"
hash=$(echo -n "$cluster_service_db" | md5sum | cut -c1-10)
cluster_service_username="cluster_serivce_${hash}"
cluster_service_secret_name="${env}-${logical_region_name}-rds-cluster-service-pawssword"
cluster_service_passowrd=$(create_or_get_secret "$cluster_service_secret_name" "$cluster_service_username")
create_user_and_db "$cluster_service_db" "$cluster_service_username" "$cluster_service_passowrd"
echo "===================== create cluster service db done ====================="

config_center_db="${env}_${db_logical_region_name}_config_center"
hash=$(echo -n "$config_center_db" | md5sum | cut -c1-10)
config_center_username="config_center_${hash}"
config_center_secret_name="${env}-${logical_region_name}-rds-config-center-pawssword"
config_center_passowrd=$(create_or_get_secret "$config_center_secret_name" "$config_center_username")
create_user_and_db "$config_center_db" "$config_center_username" "$config_center_passowrd"
echo "===================== create config center db done ====================="

if [[ -n "$proxy_name" ]]; then
  new_secret_names=(
      $cluster_service_secret_name
      $config_center_secret_name
  )
  current_auth=$(aws rds describe-db-proxies \
    --db-proxy-name "$proxy_name" \
    --query "DBProxies[0].Auth" \
    --output json)
  echo "🔍 Current auth: $current_auth"

  current_secret_arns=$(echo "$current_auth" | jq -r '.[].SecretArn')
  merged_auth=$current_auth

  updated=false
  for secret_name in "${new_secret_names[@]}"; do
    secret_arn=$(aws secretsmanager describe-secret \
      --secret-id "$secret_name" \
      --query "ARN" \
      --output text)

    if [[ -z "$secret_arn" ]]; then
      echo "❌ Secret $secret_name not found"
      exit 1
    elif echo "$current_secret_arns" | grep -q "$secret_arn"; then
      echo "✔ Secret $secret_name ($secret_arn) already exists"
    else
      echo "➕ Adding new secret: $secret_name ($secret_arn)"
      template=$(echo "$current_auth" | jq '.[0] | del(.SecretArn)')
      new_entry=$(echo "$template" | jq --arg arn "$secret_arn" --arg desc "$cluster" '. + {SecretArn:$arn,Description:$desc}')
      merged_auth=$(echo "$merged_auth" | jq --argjson entry "$new_entry" '. + [$entry]')
      updated=true
    fi
  done
  echo "📝 Final merged auth: $merged_auth"

  if $updated; then
    aws rds modify-db-proxy \
      --db-proxy-name "$proxy_name" \
      --auth "$merged_auth"
    echo "✅ Proxy $proxy_name updated"
  else
    echo "✔ No changes needed for proxy $proxy_name."
  fi
fi

local_output=/tmp/output.yaml
remote_output=$(yq '.outputPath' "${local_config}")
cat <<EOF > "${local_output}"
cluster_service:
  host: "$rds_host"
  port: $rds_port
  db: "$cluster_service_db"
  username: "$cluster_service_username"
  password_secret_name: "$cluster_service_secret_name"
config_center:
  host: "$rds_host"
  port: $rds_port
  db: "$config_center_db"
  username: "$config_center_username"
  password_secret_name: "$config_center_secret_name" 
EOF
echo "Write output to S3..."
aws s3 cp "${local_output}" "${remote_output}" --region=$output_bucket_region
