#!/usr/bin/env bash
set -euo pipefail
# This script should be idempotent and retriable
# It's used to deploy a new region
# When adding a new dataplane aws account, this script should be
# invoked several times, each with a single region
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

action=$(yq '.jobOptions.iam.action // "apply"' "${local_config}")
output_command="terraform output -json"
if [[ "${action}" == "apply" ]]; then
  action="apply -auto-approve"
elif [[ "${action}" == "plan" ]]; then
  action="plan -out=tfplan.binary"
  output_command="terraform show -json tfplan.binary | jq '(.planned_values.outputs // {} | with_entries(.value.value = if .value.value == null then \"known-after-apply\" else .value.value end) )'"
fi
cloud=$(yq '.cloudProvider' "${local_config}")
env=$(yq '.env' "${local_config}")
globalEnv=$(yq ".globalEnv // \"$env\"" "${local_config}")
region=$(yq '.region' "${local_config}")
logicalRegionName=$(yq '.name' "${local_config}")
cluster=$(yq '.k8s.name' "${local_config}")
eks_oidc=$(yq '.k8s.oidcIssuer' "${local_config}" | sed -E 's/^\s*.*:\/\///g')
controlplane_account=$(yq '.aws.controlplaneAccount' "${local_config}")
dataplane_accounts_json=$(yq -ojson '.aws.dataplaneAccounts' "${local_config}" | jq -c '.')
dataplane_accounts=$(yq -ojson '.aws.dataplaneAccounts' "${local_config}" | jq -r '.[]')
job_id=$(yq '.jobId' "${local_config}")
remote_output=$(yq '.outputPath' "${local_config}")
local_output=/tmp/output.yaml
ROOT=$(cd $(dirname "${BASH_SOURCE[0]}") && pwd)
tf_directory="${ROOT}/iam_tf"
tf_s3_bucket=$(yq '.terraformStateBucket' "${local_config}")
tf_s3_region=$(aws s3api get-bucket-location --bucket $tf_s3_bucket --region $region --query "LocationConstraint" --output text)

# Provision crossplane iam role in controlplane account
module_path="crossplane-aws-provider/controlplane"
cd "${tf_directory}/${module_path}"
tf_state="${module_path}/${controlplane_account}-${env}-${logicalRegionName}-tfstate.json"
terraform init -backend-config="bucket=${tf_s3_bucket}" -backend-config="key=${tf_state}" -backend-config="region=${tf_s3_region}"
terraform ${action} -var="env=${env}" \
  -var="controlplane_account=${controlplane_account}" \
  -var="eks_oidc=${eks_oidc}" \
  -var="logical_region_name=${logicalRegionName}"
crossplane_role_arn=$(eval $output_command | jq -r '.role_arn.value') # We need to strip the quote with -r option

# Provision eks-service iam role in dataplane account
module_path="eks-service/dataplane"
cd "${tf_directory}/${module_path}"
eks_service_role_name="${env}-${logicalRegionName}-eks-service-role"
for acct in ${dataplane_accounts[@]}; do
  tf_state="${module_path}/${acct}-${env}-${logicalRegionName}-tfstate.json"
  terraform init -reconfigure -backend-config="bucket=${tf_s3_bucket}" -backend-config="key=${tf_state}" -backend-config="region=${tf_s3_region}"
  terraform ${action} -var="role_name=${eks_service_role_name}" -var="account=${acct}"
done

# Provision cluster-controller iam role in controlplane account
module_path="cluster-controller/controlplane"
cd "${tf_directory}/${module_path}"
tf_state="${module_path}/${controlplane_account}-${env}-${logicalRegionName}-tfstate.json"
terraform init -backend-config="bucket=${tf_s3_bucket}" -backend-config="key=${tf_state}" -backend-config="region=${tf_s3_region}"
terraform ${action} -var="env=${env}" \
  -var="controlplane_account=${controlplane_account}" \
  -var="dataplane_accounts=${dataplane_accounts_json}" \
  -var="eks_oidc=${eks_oidc}" \
  -var="crossplane_role_arn=${crossplane_role_arn}" \
  -var="logical_region_name=${logicalRegionName}"
cluster_server_role_arn=$(eval $output_command | jq '.cluster_server_role_arn.value')
cluster_controller_role_arn=$(eval $output_command | jq '.role_arn.value')
readonly_cluster_controller_role_arn=$(eval $output_command | jq '.readonly_role_arn.value')
cluster_controller_assumed_role_name=$(eval $output_command | jq '.assumed_role_name.value')
readonly_cluster_controller_assumed_role_name=$(eval $output_command | jq '.readonly_assumed_role_name.value')
cluster_controller_xp_controlplane_role_arn=$(eval $output_command | jq '.crossplane_assumed_role_arn.value')
# Provision cluster-controller assumed role in dataplane accounts
module_path="cluster-controller/dataplane"
cd "${tf_directory}/${module_path}"
cluster_controller_controlplane_role_arns="[${cluster_controller_role_arn}, ${cluster_controller_xp_controlplane_role_arn}, \"${crossplane_role_arn}\"]" # $crossplane_role_arn has removed quote
readonly_cluster_controller_controlplane_role_arns="[${readonly_cluster_controller_role_arn}]"
cluster_controller_dataplane_assumed_role_arns=()
for acct in ${dataplane_accounts[@]}; do
  tf_state="${module_path}/${acct}-${env}-${logicalRegionName}-tfstate.json"
  terraform init -reconfigure -backend-config="bucket=${tf_s3_bucket}" -backend-config="key=${tf_state}" -backend-config="region=${tf_s3_region}"
  terraform ${action} -var="env=${env}" -var="account=${acct}" \
    -var="controlplane_role_arns=${cluster_controller_controlplane_role_arns}" \
    -var="readonly_controlplane_role_arns=${readonly_cluster_controller_controlplane_role_arns}" \
    -var="logical_region_name=${logicalRegionName}"
  assumed_role_arn=$(eval $output_command | jq -r '.assumed_role_arn.value')
  cluster_controller_dataplane_assumed_role_arns+=( $assumed_role_arn )
done
cluster_controller_dataplane_assumed_role_arns_json=$(jq --compact-output --null-input '$ARGS.positional' --args -- "${cluster_controller_dataplane_assumed_role_arns[@]}")

# Provision ticdc-controller iam role in controlplane account
module_path="ticdc-service/controlplane"
cd "${tf_directory}/${module_path}"
tf_state="${module_path}/${controlplane_account}-${env}-${logicalRegionName}-tfstate.json"
terraform init -backend-config="bucket=${tf_s3_bucket}" -backend-config="key=${tf_state}" -backend-config="region=${tf_s3_region}"
terraform ${action} -var="env=${env}" \
  -var="controlplane_account=${controlplane_account}" \
  -var="dataplane_accounts=${dataplane_accounts_json}" \
  -var="eks_oidc=${eks_oidc}" \
  -var="logical_region_name=${logicalRegionName}"
ticdc_server_role_arn=$(eval $output_command | jq '.ticdc_server_role_arn.value')
ticdc_controller_role_arn=$(eval $output_command | jq '.ticdc_controller_role_arn.value')
ticdc_controller_assumed_role_name=$(eval $output_command | jq '.ticdc_controller_assumed_role_name.value')
# Provision ticdc-controller assumed role in dataplane accounts
module_path="ticdc-service/dataplane"
cd "${tf_directory}/${module_path}"
ticdc_controller_dataplane_assumed_role_arns=()
for acct in ${dataplane_accounts[@]}; do
  tf_state="${module_path}/${acct}-${env}-${logicalRegionName}-tfstate.json"
  terraform init -reconfigure -backend-config="bucket=${tf_s3_bucket}" -backend-config="key=${tf_state}" -backend-config="region=${tf_s3_region}"
  terraform ${action} -var="env=${env}" -var="account=${acct}" \
    -var="controlplane_role_arns=[\"${crossplane_role_arn}\",$ticdc_controller_role_arn]" \
    -var="logical_region_name=${logicalRegionName}"
  assumed_role_arn=$(eval $output_command | jq -r '.assumed_role_arn.value')
  ticdc_controller_dataplane_assumed_role_arns+=( $assumed_role_arn )
done
ticdc_controller_dataplane_assumed_role_arns_json=$(jq --compact-output --null-input '$ARGS.positional' --args -- "${ticdc_controller_dataplane_assumed_role_arns[@]}")

# Provision region-server iam role in controlplane account
module_path="region-server/controlplane"
cd "${tf_directory}/${module_path}"
tf_state="${module_path}/${controlplane_account}-${env}-${logicalRegionName}-tfstate.json"
terraform init -backend-config="bucket=${tf_s3_bucket}" -backend-config="key=${tf_state}" -backend-config="region=${tf_s3_region}"
terraform ${action} -var="env=${env}" \
  -var="controlplane_account=${controlplane_account}" \
  -var="dataplane_accounts=${dataplane_accounts_json}" \
  -var="eks_oidc=${eks_oidc}" \
  -var="crossplane_role_arn=${crossplane_role_arn}" \
  -var="logical_region_name=${logicalRegionName}"
region_server_role_arn=$(eval $output_command | jq '.role_arn.value')
region_server_assumed_role_name=$(eval $output_command | jq '.assumed_role_name.value')
region_server_xp_controlplane_role_arn=$(eval $output_command | jq '.crossplane_assumed_role_arn.value')
# Provision region-server assumed role in dataplane accounts
module_path="region-server/dataplane"
cd "${tf_directory}/${module_path}"
region_server_controlplane_role_arns="[${region_server_role_arn}, ${region_server_xp_controlplane_role_arn}, \"${crossplane_role_arn}\"]" # $crossplane_role_arn has removed quote
for acct in ${dataplane_accounts[@]}; do
  tf_state="${module_path}/${acct}-${env}-${logicalRegionName}-tfstate.json"
  terraform init -reconfigure -backend-config="bucket=${tf_s3_bucket}" -backend-config="key=${tf_state}" -backend-config="region=${tf_s3_region}"
  terraform ${action} -var="env=${env}" -var="account=${acct}" \
    -var="controlplane_role_arns=${region_server_controlplane_role_arns}" \
    -var="logical_region_name=${logicalRegionName}"
done

# Provision tcidm iam role in controlplane account
module_path="tcidm/controlplane"
cd "${tf_directory}/${module_path}"
tf_state="${module_path}/${controlplane_account}-${env}-${logicalRegionName}-tfstate.json"
terraform init -backend-config="bucket=${tf_s3_bucket}" -backend-config="key=${tf_state}" -backend-config="region=${tf_s3_region}"
terraform ${action} -var="env=${env}" \
  -var="controlplane_account=${controlplane_account}" \
  -var="dataplane_accounts=${dataplane_accounts_json}" \
  -var="eks_oidc=${eks_oidc}" \
  -var="logical_region_name=${logicalRegionName}"
dm_controllerr_role_arn=$(eval $output_command | jq '.dm_controller_role_arn.value')
import_controllerr_role_arn=$(eval $output_command | jq '.import_controller_role_arn.value')
dm_controllerr_assumed_role_name=$(eval $output_command | jq '.dm_controller_assumed_role_name.value')
import_controllerr_assumed_role_name=$(eval $output_command | jq '.import_controller_assumed_role_name.value')
# Provision tcidm assumed role in dataplane accounts
module_path="tcidm/dataplane"
cd "${tf_directory}/${module_path}"
dm_controller_controlplane_role_arns="[${dm_controllerr_role_arn}, \"${crossplane_role_arn}\"]" # $crossplane_role_arn has removed quote
import_controller_controlplane_role_arns="[${import_controllerr_role_arn}, \"${crossplane_role_arn}\"]" # $crossplane_role_arn has removed quote
dm_controller_dataplane_assumed_role_arns=()
import_controller_dataplane_assumed_role_arns=()
for acct in ${dataplane_accounts[@]}; do
  tf_state="${module_path}/${acct}-${env}-${logicalRegionName}-tfstate.json"
  terraform init -reconfigure -backend-config="bucket=${tf_s3_bucket}" -backend-config="key=${tf_state}" -backend-config="region=${tf_s3_region}"
  terraform ${action} -var="env=${env}" -var="account=${acct}" \
    -var="dm_controlplane_role_arns=${dm_controller_controlplane_role_arns}" \
    -var="import_controlplane_role_arns=${import_controller_controlplane_role_arns}" \
    -var="logical_region_name=${logicalRegionName}"
  dm_controller_assumed_role_arn=$(eval $output_command | jq -r '.dm_controller_assumed_role_arn.value')
  import_controller_assumed_role_arn=$(eval $output_command | jq -r '.import_controller_assumed_role_arn.value')
  dm_controller_dataplane_assumed_role_arns+=( $dm_controller_assumed_role_arn )
  import_controller_dataplane_assumed_role_arns+=( $import_controller_assumed_role_arn )
done
dm_controller_dataplane_assumed_role_arns_json=$(jq --compact-output --null-input '$ARGS.positional' --args -- "${dm_controller_dataplane_assumed_role_arns[@]}")
import_controller_dataplane_assumed_role_arns_json=$(jq --compact-output --null-input '$ARGS.positional' --args -- "${import_controller_dataplane_assumed_role_arns[@]}")

# Provision cert-manager iam role in controlplane account
module_path="cert-manager/controlplane"
cd "${tf_directory}/${module_path}"
tf_state="${module_path}/${controlplane_account}-${env}-${logicalRegionName}-tfstate.json"
terraform init -backend-config="bucket=${tf_s3_bucket}" -backend-config="key=${tf_state}" -backend-config="region=${tf_s3_region}"
terraform ${action} -var="env=${env}" \
  -var="controlplane_account=${controlplane_account}" \
  -var="eks_oidc=${eks_oidc}" \
  -var="logical_region_name=${logicalRegionName}"
cert_manager_role_arn=$(eval $output_command | jq '.role_arn.value')

# Provision external-secrets-operator iam role in controlplane account
module_path="external-secrets-operator/controlplane"
cd "${tf_directory}/${module_path}"
tf_state="${module_path}/${controlplane_account}-${env}-${logicalRegionName}-tfstate.json"
terraform init -backend-config="bucket=${tf_s3_bucket}" -backend-config="key=${tf_state}" -backend-config="region=${tf_s3_region}"
terraform ${action} -var="env=${env}" -var="secret_prefix=${globalEnv}" \
  -var="controlplane_account=${controlplane_account}" \
  -var="eks_oidc=${eks_oidc}" \
  -var="logical_region_name=${logicalRegionName}"
external_secrets_operator_role_arn=$(eval $output_command | jq '.role_arn.value')

# Provision aws-lb-controller iam role in controlplane account
module_path="aws-load-balancer-controller/controlplane"
cd "${tf_directory}/${module_path}"
tf_state="${module_path}/${controlplane_account}-${env}-${logicalRegionName}-tfstate.json"
terraform init -backend-config="bucket=${tf_s3_bucket}" -backend-config="key=${tf_state}" -backend-config="region=${tf_s3_region}"
terraform ${action} -var="env=${env}" \
  -var="controlplane_account=${controlplane_account}" \
  -var="eks_oidc=${eks_oidc}" \
  -var="logical_region_name=${logicalRegionName}"
aws_load_balancer_controller_role_arn=$(eval $output_command | jq '.role_arn.value')

# Provision cluster autoscaler iam role in controlplane account
module_path="cluster-autoscaler/controlplane"
cd "${tf_directory}/${module_path}"
tf_state="${module_path}/${controlplane_account}-${env}-${logicalRegionName}-tfstate.json"
terraform init -backend-config="bucket=${tf_s3_bucket}" -backend-config="key=${tf_state}" -backend-config="region=${tf_s3_region}"
terraform ${action} -var="env=${env}" \
  -var="controlplane_account=${controlplane_account}" \
  -var="eks_oidc=${eks_oidc}" \
  -var="logical_region_name=${logicalRegionName}"
cluster_autoscaler_role_arn=$(eval $output_command | jq '.role_arn.value')

# Provision dp-provider iam role in controlplane account
module_path="dp-provider/controlplane"
cd "${tf_directory}/${module_path}"
tf_state="${module_path}/${controlplane_account}-${env}-${logicalRegionName}-tfstate.json"
terraform init -backend-config="bucket=${tf_s3_bucket}" -backend-config="key=${tf_state}" -backend-config="region=${tf_s3_region}"
terraform ${action} -var="env=${env}" \
  -var="controlplane_account=${controlplane_account}" \
  -var="eks_oidc=${eks_oidc}" \
  -var="logical_region_name=${logicalRegionName}"
dp_provider_role_arn=$(eval $output_command | jq '.role_arn.value')
dp_provider_assumed_role_name=$(eval $output_command | jq '.assumed_role_name.value')

vector_role_arn=""
assume_o11y_role_arn=$(yq -ojson '.jobOptions.vector.o11yRoleArn' "${local_config}" | jq -r '.[]')
module_path="vector-agent/controlplane"
cd "${tf_directory}/${module_path}"
tf_state="${module_path}/${controlplane_account}-${env}-${logicalRegionName}-tfstate.json"
terraform init -backend-config="bucket=${tf_s3_bucket}" -backend-config="key=${tf_state}" -backend-config="region=${tf_s3_region}"
terraform ${action} -var="env=${env}" \
  -var="logical_region_name=${logicalRegionName}" \
  -var="controlplane_account=${controlplane_account}" \
  -var="assume_o11y_role_arn=${assume_o11y_role_arn}" \
  -var="eks_oidc=${eks_oidc}"

vector_role_arn=$(eval $output_command | jq '.role_arn.value')

cat <<EOF > "${local_output}"
clusterServer:
  roleArn: ${cluster_server_role_arn}
clusterController:
  roleArn: ${cluster_controller_role_arn}
  readonlyRoleArn: ${readonly_cluster_controller_role_arn}
  dataplaneRoleName: ${cluster_controller_assumed_role_name}
  readonlyDataplaneRoleName: ${readonly_cluster_controller_assumed_role_name}
  globalRoleArn: ${cluster_controller_xp_controlplane_role_arn}
  dataplaneRoleArns: $cluster_controller_dataplane_assumed_role_arns_json
ticdcService:
  controllerRoleArn: ${ticdc_controller_role_arn}
  serverRoleArn: ${ticdc_server_role_arn}
  dataplaneRoleName: ${ticdc_controller_assumed_role_name}
  dataplaneRoleArns: $ticdc_controller_dataplane_assumed_role_arns_json
regionServer:
  roleArn: ${region_server_role_arn}
  dataplaneRoleName: ${region_server_assumed_role_name}
  globalRoleArn: ${region_server_xp_controlplane_role_arn}
  eksServiceRoleName: ${eks_service_role_name}
crossplaneAwsProvider:
  roleArn: ${crossplane_role_arn}
certManager:
  roleArn: ${cert_manager_role_arn}
externalSecretsOperator:
  roleArn: ${external_secrets_operator_role_arn}
awsLoadBalancerController:
  roleArn: ${aws_load_balancer_controller_role_arn}
clusterAutoscaler:
  roleArn: ${cluster_autoscaler_role_arn}
dpProvider:
  roleArn: ${dp_provider_role_arn}
  dataplaneRoleName: ${dp_provider_assumed_role_name}
tcidm:
  dmRoleArn: ${dm_controllerr_role_arn}
  dmAssumeRoleName: ${dm_controllerr_assumed_role_name}
  dmDataplaneRoleArns: ${dm_controller_dataplane_assumed_role_arns_json}
  importRoleArn: ${import_controllerr_role_arn}
  importAssumeRoleName: ${import_controllerr_assumed_role_name}
  importDataplaneRoleArns: ${import_controller_dataplane_assumed_role_arns_json}
vector:
  roleArn: ${vector_role_arn}
EOF
echo "Write output to S3..."
aws s3 cp "${local_output}" "${remote_output}" --region=$output_bucket_region
