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

ROOT=$(cd $(dirname "${BASH_SOURCE[0]}") && pwd)
source "$ROOT/lib.sh"

timeout=${JOB_TIMEOUT:=300} # 5min
interval=${JOB_CHECK_INTERVAL:=10}

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}")
export AWS_REGION=$region
logicalRegionName=$(yq '.name' "${local_config}")
env=$(yq '.env' "${local_config}")
cloud=$(yq '.cloudProvider' "${local_config}")
cluster=$(yq '.k8s.name' "${local_config}")
jobId=$(yq '.jobId' "${local_config}")
remote_output=$(yq '.outputPath' "${local_config}")
image_registry=$(yq '.imageRegistry' "${local_config}")
o11y_enabled=$(yq '.jobOptions.o11y.enabled' "${local_config}")

if [ "${o11y_enabled}" != "true" ]; then
  echo "o11y is not enabled, skipping o11y-agent deployment"
  exit 0
fi

auth0_secret_id=$(yq '.jobOptions.o11y.auth0SecretID' "${local_config}")
# read client secret using aws cli from aws secret manager
secret_string=$(aws secretsmanager get-secret-value --secret-id ${auth0_secret_id} --query SecretString --region us-west-2 --output text)
client_id=$(echo ${secret_string} | jq -r .Auth0ClientID)
client_secret=$(echo ${secret_string} | jq -r .Auth0ClientSecret)

o11y_global_endpoint=$(yq '.jobOptions.o11y.globalEndpoint' "${local_config}")
o11y_tenant_id=$(yq '.jobOptions.o11y.tenantId' "${local_config}")
o11y_project_id=$(yq '.jobOptions.o11y.projectId' "${local_config}")
o11y_rule_template_id=$(yq '.jobOptions.o11y.ruleTemplateId' "${local_config}")
o11y_private_link_zone=$(yq '.jobOptions.o11y.privateLinkZone' "${local_config}")

remote_iam_config=$(yq '.jobOutput.iam' "${local_config}")
local_iam_config=/tmp/iam-config.yaml
aws s3 cp ${remote_iam_config} ${local_iam_config} --region=$output_bucket_region
vector_role_arn=$(yq '.vector.roleArn' "${local_iam_config}")

echo "===================== start check o11y cluster created ====================="
resp=$(
  curl --location --request POST 'https://tidb-soc2.us.auth0.com/oauth/token' \
    --header 'content-type: application/x-www-form-urlencoded' \
    --data-urlencode 'grant_type=client_credentials' \
    --data-urlencode "client_id=${client_id}" \
    --data-urlencode "client_secret=${client_secret}" \
    --data-urlencode 'audience=https://tidb-soc2.us.auth0.com/api/v2/'
)

echo "get token resp: $resp"

access_token=$(echo "$resp" | jq -r '.access_token')
token="Bearer ${access_token}"

application_id="$logicalRegionName"
biz_type="${env}-tidbcloud"
if [ "$env" == "prod" ]; then
    biz_type="tidbcloud"
fi
seed_o11y_cluster_tag="auto-deploy-cli-created"

create_cluster_body=$(cat <<EOF
{
  "vendor": "${cloud}",
  "region": "${region}",
  "tenantID": "${o11y_tenant_id}",
  "projectID": "${o11y_project_id}",
  "applicationID": "${application_id}",
  "bizType": "${biz_type}",
  "version": "v1",
  "shareMode": "shared",
  "dataPropertyRights": 1,
  "agentAccessARN": "${vector_role_arn}",
  "ruleTemplateID": "${o11y_rule_template_id}",
  "tags": [
    "$seed_o11y_cluster_tag"
  ]
}
EOF
)

# create o11y cluster by calling o11y createCluster global api
create_cluster_resp=$(
  curl -XPOST --location "http://${o11y_global_endpoint}/api/v1/clusters/" \
  --header "Authorization: ${token}" \
  --header "Content-Type: application/json" \
  --data "${create_cluster_body}"
)
echo "create_cluster_resp: $create_cluster_resp"
create_code=$(echo -n "$create_cluster_resp" | jq -r '.code')
# 1003 means already exists, 0 means created cluster
if [[ "$create_code" -ne 0 && "$create_code" -ne 1003 ]]; then
  echo "Failed to create o11y cluster, code: $create_code"
  exit 1
fi

resp=$(curl -XGET -sL --location "http://${o11y_global_endpoint}/api/v1/clusters?bizType=$biz_type&region=$region&tenantID=$o11y_tenant_id&vendor=$cloud&projectID=$o11y_project_id&applicationID=$application_id" \
  --header "Authorization: ${token}" \
  --header "Content-Type: application/json")
o11y_cluster_id=$(echo "$resp" | jq -r '.data.clusters[0].id')
echo "o11y_cluster_id: $o11y_cluster_id"

# check o11y cluster tag
cluster_info=$(echo -n "$resp" | jq -r '.data.clusters[0]')
tags_count=$(echo "$cluster_info" | jq -r '.tags | length')
not_found="true"
for ((i=0; i<$tags_count; i++)); do
  tag=$(echo "$cluster_info" | jq -r ".tags[$i]")
  if [ "$tag" == "$seed_o11y_cluster_tag" ]; then
    not_found="false"
    break
  fi
done
if "$not_found"; then
  echo "o11y cluster $o11y_cluster_id is not created by auto deploy cli"
  exit 1
fi

# wait o11y cluster ready
status=$(echo -n "$cluster_info" | jq -r '.status')
start_time=$(date +%s)
while [[ $(($(date +%s) - $start_time)) -lt $timeout ]]; do
  get_cluster_resp=$(
    curl -XGET --location "http://${o11y_global_endpoint}/api/v1/clusters/${o11y_cluster_id}?vendor=${cloud}&region=${region}" \
    --header "Authorization: ${token}" \
    --header "Content-Type: application/json"
  )
  echo "get_cluster_resp: $get_cluster_resp"
  cluster_info=$(echo -n "$get_cluster_resp"| jq -r '.data')
  status=$(echo -n "$cluster_info" | jq -r '.status')

  if [ $status == "ACTIVE" ]; then
    echo "o11y cluster is ready!"
    break
  else
    sleep "${interval}"
  fi
done

log_bucket_name=$(echo "$cluster_info" | jq -r '.storageInfo[] | select(.category == "logs") | .bucketName')
assume_o11y_role=$(echo "$cluster_info" | jq -r '.agentInfo.roleARN')
endpoint_service_name=$(echo "$cluster_info" | jq -r '.monitorInfo.endpointServiceName')
endpoint_dns_name=$(echo "$cluster_info" | jq -r '.monitorInfo.dnsName')
echo "===================== create o11y cluster done and ready ====================="

echo "===================== create private endpoint things ====================="
vpc_id=$(aws eks describe-cluster \
  --name $cluster \
  --query "cluster.resourcesVpcConfig.vpcId" \
  --output text)
echo "found vpc: $vpc_id"

# find target subnet
subnet_info=$(aws ec2 describe-subnets \
  --filters "Name=vpc-id,Values=$vpc_id" "Name=availability-zone,Values=$o11y_private_link_zone" "Name=tag:Name,Values=*${cluster}-cluster/SubnetPrivate*" \
  --query "Subnets[0].{SubnetId:SubnetId, Name:Tags[?Key=='Name'].Value | [0]}" \
  --output json)
subnet_id=$(echo $subnet_info | jq -r '.SubnetId')
subnet_name=$(echo $subnet_info | jq -r '.Name')
if [ -z "$subnet_id" ]; then
  echo "Error: No private subnet found in VPC $vpc_id"
  exit 1
fi

echo "found subnet: $subnet_name $subnet_id"

sg_name=${env}-seed-o11y-metrics-sg
security_group_id=""
# create security group for o11y agent 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 o11y agent" \
  --tag-specifications ResourceType=security-group,Tags="[{Key=Name,Value=$sg_name}]" \
  --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 80 --cidr 0.0.0.0/0
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
existing_endpoint=$(aws ec2 describe-vpc-endpoints --filters "Name=vpc-id,Values=$vpc_id" --query "VpcEndpoints[?ServiceName=='$endpoint_service_name']" --output text)
if [ -z "$existing_endpoint" ]; then
  aws ec2 create-vpc-endpoint --private-dns-enabled --vpc-id $vpc_id \
  --service-name $endpoint_service_name \
  --vpc-endpoint-type Interface \
  --subnet-id $subnet_id \
  --security-group-id $security_group_id
fi
echo "===================== create private endpoint done ====================="

additionalArgs=$(cat <<EOF
{
  "vectorRoleARN": "$vector_role_arn",
  "assumeO11yRole": "$assume_o11y_role",
  "logBucketName": "$log_bucket_name",
  "imageRegistry": "$image_registry",
  "tenantId": "$o11y_tenant_id",
  "projectId": "$o11y_project_id",
  "o11yId": "$o11y_cluster_id",
  "clusterName": "$cluster",
  "o11yEndpointServiceDNSName": "$endpoint_dns_name"
}
EOF
)
echo "additionalArgs: $additionalArgs"

# Deploy application services by invoking deploy-new-region action in $argocd_repo
common_params="-f cloud=${cloud} -f region=${region} -f env=${env} -f cluster=${cluster} -f jobId=${jobId} -f logicalRegionName=${logicalRegionName}"

export GH_REPO="${argocd_repo}"
gh workflow run deploy-new-region-o11y-agent.yaml ${common_params} -f additionalArgs="${additionalArgs}"

# Wait services ready
declare -A services
services["sts/vmagent-$env-seed-$logicalRegionName-o11y"]="false"
namespace="monitoring"
wait_for_services_ready services namespace
if [[ $? -eq 1 ]]; then
    echo "Services are not ready"
    exit 1
fi

local_output=/tmp/output.yaml
cat <<EOF > "${local_output}"
o11y_cluster_id: $o11y_cluster_id
EOF
echo "Write output to S3..."
aws s3 cp "${local_output}" "${remote_output}" --region=$output_bucket_region
