#!/usr/bin/env bash

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

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

disabled=$(yq '.jobOptions.dpProvider.disabled' "${local_config}")
if [[ $disabled == "true" ]]; then
  echo "job is disabled, exit"
  exit 0
fi

argocd_repo=tidbcloud/app-delivery
region=$(yq '.region' "${local_config}")
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}")
output=$(yq '.outputPath' "${local_config}")

# can't need to remove secret replication

# 2. append the regional control plane outbound ips to global api gateway inner WAF ip set
waf_ip_set_name=$(yq '.jobOptions.dpProvider.wafIpSetName' "${local_config}")
echo "waf_ip_set_name: \"$waf_ip_set_name\""
if [[ ! -z $waf_ip_set_name ]]; then
  outbound_ips=$(yq -ojson '.k8s.publicIps | map(. + "/32")' "${local_config}")
  waf_ip_set_id=$(aws wafv2 list-ip-sets --scope REGIONAL --region us-west-2 | jq -r ".IPSets[] | select(.Name==\"${waf_ip_set_name}\") | .Id")
  waf_retry_num=0
  waf_max_retry_num=5
  while true; do
    waf_ip_set_json=$(aws wafv2 get-ip-set --scope REGIONAL --region us-west-2 --name "${waf_ip_set_name}" --id "${waf_ip_set_id}")
    waf_ip_set_addrs=$(echo "${waf_ip_set_json}" | jq -r '.IPSet.Addresses')
    waf_ip_set_lock_token=$(echo "${waf_ip_set_json}" | jq -r '.LockToken')
    update_waf_ip_set_addrs=$(echo "${waf_ip_set_addrs}" | jq ". -= ${outbound_ips}" | jq -r '.[]' | tr '\n' ' ') # use minus to remove ip from ip set
    aws wafv2 update-ip-set --scope REGIONAL --region us-west-2 --name "${waf_ip_set_name}" --id "${waf_ip_set_id}" --lock-token "${waf_ip_set_lock_token}" --addresses ${update_waf_ip_set_addrs}
    if [[ $? == 0 ]]; then
      echo "update ip set ${waf_ip_set_name} successfully"
      break
    fi
    echo "update ip set ${waf_ip_set_name} failed, retrying"
    waf_retry_num=$((waf_retry_num + 1))
    if [[ ${waf_retry_num} -ge ${waf_max_retry_num} ]]; then
      echo "retry updating ip set timeout"
      exit 1
    else
      sleep 5
    fi
  done
fi


if [[ $env != "prod" ]]; then
  exit 0
fi
# 3. append the regional control plane outbound ips to infra-api-server LB allow list
infra_cd_repo=https://$GH_TOKEN@github.com/tidbcloud/infra-cd.git
main_branch=main
release_branch=gardener-arch/release-0.53

# 3.1 update the pulumi configuration file and merge to the main branch
repo_name=$(basename ${infra_cd_repo} .git)
timestamp=$(date +%s)
update_branch="deploy-job-${timestamp}"
git clone ${infra_cd_repo}
cd "${repo_name}"
git remote set-url origin ${infra_cd_repo}
git checkout -b "${update_branch}"
api_server_conf_path=projects/apiserver/Pulumi.prod.yaml
existing_ips=$(yq ".config.\"infra-apiserver:public-access-cidrs\"" ${api_server_conf_path})
remove_ips=$(yq '.k8s.publicIps | map(. + "/32") | .[]' ${local_config})
remove_ips_json=$(yq -ojson '.k8s.publicIps | map(. + "/32")' ${local_config})
combined_ips=$(echo "${existing_ips}" | grep -vF "$remove_ips" | uniq)
existing_lines_count=$(echo "${existing_ips}" | wc -l)
combined_lines_count=$(echo "${combined_ips}" | wc -l)
if [[ ${existing_lines_count} -eq ${combined_lines_count} ]]; then
  echo "outbound ips are already added"
  exit 0
fi
yq -i ".config.\"infra-apiserver:public-access-cidrs\" -= $remove_ips_json" ${api_server_conf_path}
if [[ ! $(git status --porcelain) ]]; then
  echo "no code changes after update ip allow list"
  exit 1
fi
git add ${api_server_conf_path}
commit_msg="deploy job ${job_id} update ${api_server_conf_path}"
git commit -m "${commit_msg}"
git push origin "${update_branch}"
gh pr create --base "${main_branch}" --head "${update_branch}" --title "${commit_msg}" --fill
pr_number=$(gh pr view --json number --jq .number)
echo "PR #${pr_number} created"
gh pr merge ${pr_number} --squash --admin
echo "PR #${pr_number} merged"

# 3.2 cherry-pick the commit to the release branch
update_commit=$(git log -1 --pretty=format:"%H")
git checkout "${release_branch}"
git pull origin "${release_branch}"
cp_update_branch="cp-${update_branch}"
git checkout -b "${cp_update_branch}"
git cherry-pick "${update_commit}"
git push origin "${cp_update_branch}"
gh pr create --base "${release_branch}" --head "${cp_update_branch}" --title "${commit_msg}" --fill
pr_number=$(gh pr view --json number --jq .number)
echo "cherry-pick PR #${pr_number} created"
gh pr merge ${pr_number} --squash --admin
echo "cherry-pick PR #${pr_number} merged"

# 3.3 create a release tag base on the release branch to trigger the github action
git checkout "${release_branch}"
git pull origin "${release_branch}"
git fetch --tags
latest_tag=$(git describe --abbrev=0 --tags `git rev-list --max-count=1 --tags="gardener-arch/v*"`)
new_tag=""
if [[ $latest_tag =~ ^gardener-arch/v([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then
  major="${BASH_REMATCH[1]}"
  minor="${BASH_REMATCH[2]}"
  patch="${BASH_REMATCH[3]}"
  # Increment the patch version
  new_patch=$((patch + 1))
  new_tag="gardener-arch/v$major.$minor.$new_patch"
else
  echo "invalid tag found: ${latest_tag}, can't set new tag"
  exit 1
fi
git tag "${new_tag}"
git push origin "${new_tag}"
echo "tag ${new_tag} created"

git branch -D "${update_branch}"
git push origin --delete "${update_branch}"
git branch -D "${cp_update_branch}"
git push origin --delete "${cp_update_branch}"

# 3.4 wait for the github action complete
sleep 60
workflow_name=gardener-arch-prod-pipeline
workflow_run_id=$(gh run list --workflow "${workflow_name}" --limit 1 --json databaseId --jq '.[0].databaseId')
timeout=${JOB_TIMEOUT:=1200} # 20min
interval=${JOB_CHECK_INTERVAL:=20}
start_time=$(date +%s)
echo "waiting for workflow run ${workflow_run_id} success"
while [[ $(($(date +%s) - $start_time)) -lt $timeout ]]; do
  workflow_run_status=$(gh run view ${workflow_run_id} --json status,conclusion --jq '.status')
  if [[ ${workflow_run_status} == "completed" ]]; then
    workflow_run_conclusion=$(gh run view ${workflow_run_id} --json status,conclusion --jq '.conclusion')
    if [[ ${workflow_run_conclusion} == "success" ]]; then
      echo "workflow run ${workflow_run_id} is success"
      exit 0
    else
      echo "workflow run ${workflow_run_id} is not success, conclusion: ${workflow_run_conclusion}"
      exit 1
    fi
  else
    echo "workflow run ${workflow_run_id} status is ${workflow_run_status}, not completed, waiting"
    sleep "${interval}"
  fi
done
echo "waiting for workflow run ${workflow_run_id} timeout"
exit 1
