#!/usr/bin/env bash
set -euo pipefail
# When changing this script, remember to modify the corresponding github action
region=${1}
env=${2}
cloud=${3}
json_file_path=${4}
logicalRegionName=${5}

additional_args=$(jq -r '.' "${json_file_path}")

echo "additional_args: ${additional_args}"

irsa_role_arn=$(echo ${additional_args} | jq -r '.awsIrsaRoleArn')
default_aws_dp4drs_role=$(echo ${additional_args} | jq -r '.defaultAwsDp4DrsRole')
eks_service_role_name=$(echo ${additional_args} | jq -r '.eksServiceRoleName')
availability_zones=$(echo ${additional_args} | jq -r '.availabilityZones')
node_zones=$(echo "${additional_args}" | jq -c '.nodeZones // null')
image_registry=$(echo ${additional_args} | jq -r '.imageRegistry')
tidb_image_registry=$(echo ${additional_args} | jq -r ".tidbImageRegistry // \"${image_registry}\"")

dns_account_id=$(echo ${additional_args} | jq -r '.dnsAccountId')
dataplane_accounts=$(echo ${additional_args} | jq -r '.dataplaneAccounts')
auth0_audience=$(echo ${additional_args} | jq -r '.auth0Audience')
auth0_domain=$(echo ${additional_args} | jq -r '.auth0Domain')
global_controlplane_ips=$(echo ${additional_args} | jq -r '.globalControlplaneIPs')
regional_controlplane_ips=$(echo ${additional_args} | jq -r '.regionalControlplaneIPs')
o11y_regional_service_ips=$(echo ${additional_args} | jq -r '.o11yRegionalServiceIPs')
clinic_ips=$(echo ${additional_args} | jq -r '.clinicIPs')
bastion_ips=$(echo ${additional_args} | jq -r '.bastionIPs')
authorized_subjects=$(echo ${additional_args} | jq -r '.authorizedSubjects')
public_hosted_zone_domain=$(echo ${additional_args} | jq -r '.publicHostedZoneDomain')
public_hosted_zone_id=$(echo ${additional_args} | jq -r '.publicHostedZoneID')
dns_manager_role_arn=$(echo ${additional_args} | jq -r '.dnsManagerRoleArn')
pca_arn=$(echo ${additional_args} | jq -r '.pcaArn')
enable_kong_plugin=$(echo ${additional_args} | jq -r '.enableKongPlugin // true')
resource_name_prefix=$(echo ${additional_args} | jq -r '.resourceNamePrefix // "tidbcloud"')
enable_kong_public_access=$(echo "${additional_args}" | jq -r 'if has("enableKongPublicAccess") then .enableKongPublicAccess else true end')
node_role_name=$(echo ${additional_args} | jq -r '.nodeRoleName // "tidbcloud-eks-node-role"')
# Optional override. When unset, the template value is kept.
admin_node_instance_type=$(echo ${additional_args} | jq -r '.adminNodeInstanceType // ""')
enable_ecr_interface_endpoints=$(echo ${additional_args} | jq -r '.enableEcrInterfaceEndpoints // false')
ecr_service_region=$(echo ${additional_args} | jq -r '.ecrServiceRegion // ""')

# {
#   ...
#   "byoc": {
#     "nodeRoleName": "tidbcloud-eks-node-role",
#     "privateLink": {
#       "controlPlaneVPCID": "vpc-05f09a548e24a3cf1",
#       "controlPlaneSubnetIDs": [
#         "subnet-070da0c1147ab609a",
#         "subnet-0d8b2c9f867c2d3fc"
#       ],
#       "controlPlaneSecurityGroupIDs": ["sg-027f455a2b05673d4"]
#     }
#   }
# }
byoc=$(echo ${additional_args} | jq -r '.byoc')
o11y=$(echo "${additional_args}" | jq -c '.o11y // null')

if [ "${o11y}" != null ] && ! jq -e '
  .o11y |
  (type == "object" and
   (.vpcID | type == "string" and length > 0) and
   (.vpcCIDR | type == "string" and length > 0) and
   (.accountID | type == "string" and length > 0) and
   (.region | type == "string" and length > 0))
' <<< "${additional_args}" >/dev/null; then
  echo "Error: o11y must contain non-empty vpcID, vpcCIDR, accountID, and region when provided in additionalArgs." >&2
  exit 1
fi

if [ "${node_zones}" != null ] && ! jq -e '
  . as $args |
  ($args.availabilityZones |
    type == "array" and length > 0 and
    all(.[]; type == "string" and length > 0)) and
  ($args.nodeZones |
    type == "array" and length > 0 and
    all(.[]; type == "string" and length > 0)) and
  (($args.nodeZones - $args.availabilityZones) | length == 0) and
  (($args.nodeZones | length) < ($args.availabilityZones | length))
' <<< "${additional_args}" >/dev/null; then
  echo "Error: nodeZones must be a non-empty array of non-empty strings and a strict subset of availabilityZones when provided in additionalArgs." >&2
  exit 1
fi

ROOT=$(cd $(dirname ${BASH_SOURCE[0]}) && pwd)
deploy_dir="${ROOT}/envs/${cloud}-${env}-${logicalRegionName}"
variant_dir="${ROOT}/variants/${env}-${cloud}"

# https://stackoverflow.com/questions/4247068/sed-command-with-i-option-failing-on-mac-but-works-on-linux
if [[ "$OSTYPE" == "darwin"* ]]; then
  # Require gnu-sed.
  if ! [ -x "$(command -v gsed)" ]; then
    echo "Error: 'gsed' is not installed." >&2
    echo "If you are using Homebrew, install with 'brew install gnu-sed'." >&2
    exit 1
  fi
  SED_CMD=gsed
else
  SED_CMD=sed
fi

if [ -e ${deploy_dir} ]; then
  echo "New region deploy directory already exist"
  exit 1
fi

mkdir -p "${deploy_dir}"
echo "Prepare manifest files"
cp "${variant_dir}/kustomization_tmpl.yaml" "${deploy_dir}/kustomization.yaml"
cp "${variant_dir}/controller-version_tmpl.yaml" "${deploy_dir}/controller-version.yaml"
cp "${variant_dir}/server-version_tmpl.yaml" "${deploy_dir}/server-version.yaml"
cp "${variant_dir}/service_account_tmpl.yaml" "${deploy_dir}/service_account.yaml"

mkdir "${deploy_dir}/config"
echo "Prepare config files"
cp "${variant_dir}/config/k8s-addon-templates.yaml" "${deploy_dir}/config/k8s-addon-templates.yaml"
cp "${variant_dir}/config/k8s-dedicated-templates_tmpl.yaml" "${deploy_dir}/config/k8s-dedicated-templates.yaml"
cp "${variant_dir}/config/k8s-dp-templates_tmpl.yaml" "${deploy_dir}/config/k8s-dp-templates.yaml"
cp "${variant_dir}/config/k8s-infra-templates_tmpl.yaml" "${deploy_dir}/config/k8s-infra-templates.yaml"
cp "${variant_dir}/config/root-config_tmpl.yaml" "${deploy_dir}/config/root-config.yaml"
cp "${variant_dir}/config/cert-manager-policy-template_tmpl.json" "${deploy_dir}/config/cert-manager-policy-template.json"
# TODO: o11y-agent policy needs to be refined according to different environments
cp "${variant_dir}/config/o11y-agent-policy-template_tmpl.json" "${deploy_dir}/config/o11y-agent-policy-template.json"

disable_proxy_protocol=false

# Apply BYOC-specific template if BYOC is enabled
if [ "${byoc}" != null ]; then
  echo "Apply BYOC-specific configurations"

  disable_proxy_protocol=true

  # Merge k8s-dedicated-templates with BYOC-specific configurations
  if [ -f "${variant_dir}/config/k8s-dedicated-templates_byoc_tmpl.yaml" ]; then
    # Use yq to deep merge BYOC overlay into base template (array element at index 0)
    yq eval-all 'select(fileIndex == 0) | .[0] as $base | 
      load("'"${variant_dir}/config/k8s-dedicated-templates_byoc_tmpl.yaml"'") | .[0] as $overlay |
      [$base * $overlay]
    ' \
      "${deploy_dir}/config/k8s-dedicated-templates.yaml" \
      > "${deploy_dir}/config/k8s-dedicated-templates.yaml.tmp"
    mv "${deploy_dir}/config/k8s-dedicated-templates.yaml.tmp" "${deploy_dir}/config/k8s-dedicated-templates.yaml"
  else
    echo "Warning: BYOC template not found at ${variant_dir}/config/k8s-dedicated-templates_byoc_tmpl.yaml"
  fi

  # Enable dataplane-exporter only for BYOC regions.
  if [ -f "${variant_dir}/config/k8s-infra-templates_dataplane-exporter_tmpl.yaml" ]; then
    yq eval-all 'select(fileIndex == 0) | .[0] as $base |
      load("'"${variant_dir}/config/k8s-infra-templates_dataplane-exporter_tmpl.yaml"'") | .[0] as $overlay |
      [$base * $overlay]
    ' \
      "${deploy_dir}/config/k8s-infra-templates.yaml" \
      > "${deploy_dir}/config/k8s-infra-templates.yaml.tmp"
    mv "${deploy_dir}/config/k8s-infra-templates.yaml.tmp" "${deploy_dir}/config/k8s-infra-templates.yaml"
  else
    echo "Warning: dataplane-exporter template not found at ${variant_dir}/config/k8s-infra-templates_dataplane-exporter_tmpl.yaml"
  fi
fi

find "${deploy_dir}" -type f -exec ${SED_CMD} -i "s|TMPL_REGION|${region}|g" {} \;
${SED_CMD} -i "s|TMPL_LOGICAL_REGION|${logicalRegionName}|g" "${deploy_dir}/config/root-config.yaml"
${SED_CMD} -i "s|TMPL_IRSA_ROLE_ARN|${irsa_role_arn}|g" "${deploy_dir}/service_account.yaml"
find "${deploy_dir}" -type f -exec ${SED_CMD} -i "s|TPML_IMAGE_REGISTRY|${image_registry}|g" {} \;
find "${deploy_dir}" -type f -exec ${SED_CMD} -i "s|TPML_TIDB_IMAGE_REGISTRY|${tidb_image_registry}|g" {} \;
# replace the auth0 audience and domain
${SED_CMD} -i "s|TMPL_AUTH0_AUDIENCE|${auth0_audience}|g" "${deploy_dir}/config/k8s-dedicated-templates.yaml"
${SED_CMD} -i "s|TMPL_AUTH0_DOMAIN|${auth0_domain}|g" "${deploy_dir}/config/k8s-dedicated-templates.yaml"
# replace the public hosted zone domain and id
${SED_CMD} -i "s|TMPL_PUBLIC_HOSTED_ZONE_DOMAIN|${public_hosted_zone_domain}|g" "${deploy_dir}/config/root-config.yaml"
${SED_CMD} -i "s|TMPL_PUBLIC_HOSTED_ZONE_ID|${public_hosted_zone_id}|g" "${deploy_dir}/config/root-config.yaml"
${SED_CMD} -i "s|TMPL_DNS_MANAGER_ROLE_ARN|${dns_manager_role_arn}|g" "${deploy_dir}/config/root-config.yaml"
${SED_CMD} -i "s|TMPL_DNS_MANAGER_ACCOUNT_ID|${dns_account_id}|g" "${deploy_dir}/config/root-config.yaml"
# replace the eks service role name
${SED_CMD} -i "s|TMPL_EKS_SERVICE_ROLE_NAME|${eks_service_role_name}|g" "${deploy_dir}/config/root-config.yaml"
# replace the dataplane role
${SED_CMD} -i "s|TMPL_DATAPLANE_ROLE_NAME|${default_aws_dp4drs_role}|g" "${deploy_dir}/config/root-config.yaml"
${SED_CMD} -i "s|TMPL_RESOURCE_NAME_PREFIX|${resource_name_prefix}|g" "${deploy_dir}/config/root-config.yaml"
${SED_CMD} -i "s|TMPL_NODE_ROLE_NAME|${node_role_name}|g" "${deploy_dir}/config/root-config.yaml"
${SED_CMD} -i "s|PCA_ARN|${pca_arn}|g" "${deploy_dir}/config/cert-manager-policy-template.json"
${SED_CMD} -i "s|TMPL_DISABLE_PROXY_PROTOCOL|${disable_proxy_protocol}|g" "${deploy_dir}/config/root-config.yaml"

yq e -i ".regionConfig.zones |= $availability_zones" ${deploy_dir}/config/root-config.yaml
yq e -i ".internetConfig.enableECRInterfaceEndpoints = ${enable_ecr_interface_endpoints}" ${deploy_dir}/config/root-config.yaml
ECR_SERVICE_REGION="${ecr_service_region}" yq e -i '.internetConfig.ecrServiceRegion = strenv(ECR_SERVICE_REGION)' ${deploy_dir}/config/root-config.yaml

mkdir "${deploy_dir}/account"
echo "Prepare account-list.yaml"
# genrate the account list, ptah: account/account-list.yaml
account_list=${deploy_dir}/account/account-list.yaml
cat <<EOF > ${account_list}
accounts:
EOF

for awsAccount in $(echo ${dataplane_accounts} | jq -r '.[]'); do
  cat <<EOF >> ${account_list}
  - accountID: "${awsAccount}"
    roleName: "${default_aws_dp4drs_role}"
    externalID: ""
EOF
done

# genrate the controlplane providerconfig, path: config/providerconfig.yaml
# dataplane providerconfig will be created at dataplane-manager start time using account-list.yaml
echo "Prepare providerconfig.yaml"
providerconfig_config=${deploy_dir}/account/providerconfig.yaml
cat <<EOF > ${providerconfig_config}
---
apiVersion: aws.upbound.io/v1beta1
kind: ProviderConfig
metadata:
  name: "provider-aws"
spec:
  credentials:
    source: IRSA
EOF

root_config=${deploy_dir}/config/root-config.yaml
if [ -n "${admin_node_instance_type}" ]; then
  yq e -i ".appBoxConfig.adminNodeConfig.instanceType = \"${admin_node_instance_type}\"" ${root_config}
fi
if [ "${byoc}" != null ]; then
  yq -i ". += {\"byoc\": ${byoc}}" ${root_config}
fi
if [ "${node_zones}" != null ]; then
  yq -i ".regionConfig.nodeZones = ${node_zones}" ${root_config}
fi
if [ "${o11y}" != null ]; then
  yq -i ". += {\"o11y\": ${o11y}}" ${root_config}
fi

echo "set whitelist ip"
yq e -i ".appBoxConfig.apiserverPublicAccessCidrs |= ${bastion_ips} + ${global_controlplane_ips} + ${regional_controlplane_ips} + ${o11y_regional_service_ips}" \
  ${deploy_dir}/config/root-config.yaml

if $enable_kong_public_access; then
  yq e -i ".appBoxConfig.apiGateway.publicAccessCidrs |= ${global_controlplane_ips} + ${regional_controlplane_ips} + ${clinic_ips}" \
    ${deploy_dir}/config/root-config.yaml
else
  yq e -i "del(.appBoxConfig.apiGateway.publicAccessCidrs)" \
    ${deploy_dir}/config/root-config.yaml
  yq e -i ".appBoxConfig.apiGateway.enablePublicAccess = false" \
    ${deploy_dir}/config/root-config.yaml
fi

echo "set authorized subjects"
yq e -i ".appBoxConfig.authorizedSubjects |= ${authorized_subjects}" ${deploy_dir}/config/root-config.yaml

if $enable_kong_plugin; then
  echo "enable kong plugin"
  yq -i '.[].clusterGateway.helmValues.plugins.configMaps = [{"pluginName": "auth-server", "name":"kong-plugin-auth-server"}]' ${deploy_dir}/config/k8s-dedicated-templates.yaml
  
  # Set ingress plugins based on BYOC status
  if [ "${byoc}" != null ]; then
    # BYOC: enable auth-server and audit-kong plugins
    yq -i '.[].dataflowAgent.helmValues.ingress = {"enabled": true, "plugins": "auth-server,audit-kong"}' ${deploy_dir}/config/k8s-dp-templates.yaml
  else
    # Non-BYOC: set basic auth-server plugin only
    yq -i '.[].dataflowAgent.helmValues.ingress = {"enabled": true, "plugins": "auth-server"}' ${deploy_dir}/config/k8s-dp-templates.yaml
  fi
fi

# replace the sli config
sli_aws_region="us-west-2"
sli_delivery_stream_name="sli-dev-metrics"
sli_delivery_stream_role_arn=$(echo ${additional_args} | jq -r '.sliDeliveryStreamRoleArn')
if [ "${byoc}" != null ]; then
  sli_aws_region=${region}
  sli_delivery_stream_name="tidbcloud-sli-delivery-stream-${env}-${logicalRegionName}"
  sli_delivery_stream_role_arn=""
fi
${SED_CMD} -i "s|TPML_SLI_AWS_REGION|${sli_aws_region}|g" "${deploy_dir}/config/k8s-dedicated-templates.yaml"
${SED_CMD} -i "s|TPML_SLI_FIREHOSE_NAME|${sli_delivery_stream_name}|g" "${deploy_dir}/config/k8s-dedicated-templates.yaml"
${SED_CMD} -i "s|TPML_SLI_FIREHOSE_ROLE_ARN|${sli_delivery_stream_role_arn}|g" "${deploy_dir}/config/k8s-dedicated-templates.yaml"
