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

DEVOPS_CONTEXT="${DEVOPS_CONTEXT:-arn:aws:eks:us-west-2:552185537300:cluster/devops-staging}"
DEVOPS_NAMESPACE="${DEVOPS_NAMESPACE:-devops-staging}"
DEVOPS_SERVICE="${DEVOPS_SERVICE:-devops-server}"
DEVOPS_LOCAL_PORT="${DEVOPS_LOCAL_PORT:-18088}"
DEVOPS_REMOTE_PORT="${DEVOPS_REMOTE_PORT:-8088}"

BILLING_CONTEXT="${BILLING_CONTEXT:-arn:aws:eks:us-west-2:385595570414:cluster/staging-base-us-west-2}"
BILLING_NAMESPACE="${BILLING_NAMESPACE:-staging-ms}"
BILLING_SERVICE="${BILLING_SERVICE:-billing2-api}"
BILLING_LOCAL_PORT="${BILLING_LOCAL_PORT:-18888}"
BILLING_REMOTE_PORT="${BILLING_REMOTE_PORT:-18888}"

ACCOUNT_CONTEXT="${ACCOUNT_CONTEXT:-arn:aws:eks:us-west-2:385595570414:cluster/staging-base-us-west-2}"
ACCOUNT_NAMESPACE="${ACCOUNT_NAMESPACE:-staging-ms}"
ACCOUNT_SERVICE="${ACCOUNT_SERVICE:-account-provider-grpc}"
ACCOUNT_LOCAL_PORT="${ACCOUNT_LOCAL_PORT:-10002}"
ACCOUNT_REMOTE_PORT="${ACCOUNT_REMOTE_PORT:-10000}"

MGMT_CONTEXT="${MGMT_CONTEXT:-arn:aws:eks:us-west-2:385595570414:cluster/staging-base-us-west-2}"
MGMT_NAMESPACE="${MGMT_NAMESPACE:-tidb-management-service}"
MGMT_SERVICE="${MGMT_SERVICE:-tidb-mgmt-service}"
MGMT_LOCAL_PORT="${MGMT_LOCAL_PORT:-10001}"
MGMT_REMOTE_PORT="${MGMT_REMOTE_PORT:-10001}"

LOG_DIR="${LOG_DIR:-/tmp/jsm-syncer-port-forward}"
READY_TIMEOUT_SECONDS="${READY_TIMEOUT_SECONDS:-30}"

pids=()
names=()

require_command() {
  local name="$1"
  if ! command -v "${name}" >/dev/null 2>&1; then
    echo "missing required command: ${name}" >&2
    exit 1
  fi
}

port_is_available() {
  local port="$1"
  if ! command -v lsof >/dev/null 2>&1; then
    return 0
  fi
  ! lsof -nP -iTCP:"${port}" -sTCP:LISTEN >/dev/null 2>&1
}

wait_for_ready() {
  local name="$1"
  local pid="$2"
  local log_file="$3"
  local deadline=$((SECONDS + READY_TIMEOUT_SECONDS))

  while (( SECONDS < deadline )); do
    if grep -q "Forwarding from" "${log_file}" 2>/dev/null; then
      return 0
    fi
    if ! kill -0 "${pid}" >/dev/null 2>&1; then
      echo "${name} port-forward exited before becoming ready" >&2
      sed -n '1,120p' "${log_file}" >&2 || true
      return 1
    fi
    sleep 1
  done

  echo "${name} port-forward did not become ready within ${READY_TIMEOUT_SECONDS}s" >&2
  sed -n '1,120p' "${log_file}" >&2 || true
  return 1
}

start_port_forward() {
  local name="$1"
  local context="$2"
  local namespace="$3"
  local service="$4"
  local local_port="$5"
  local remote_port="$6"
  local log_file="${LOG_DIR}/${name}.log"

  if ! port_is_available "${local_port}"; then
    echo "local port ${local_port} is already in use for ${name}" >&2
    exit 1
  fi

  : >"${log_file}"
  kubectl \
    --context "${context}" \
    -n "${namespace}" \
    port-forward "svc/${service}" "${local_port}:${remote_port}" \
    >"${log_file}" 2>&1 &

  local pid="$!"
  pids+=("${pid}")
  names+=("${name}")

  wait_for_ready "${name}" "${pid}" "${log_file}"
  echo "${name}: 127.0.0.1:${local_port} -> ${service}:${remote_port}"
}

cleanup() {
  local status=$?
  for pid in "${pids[@]}"; do
    if kill -0 "${pid}" >/dev/null 2>&1; then
      kill "${pid}" >/dev/null 2>&1 || true
    fi
  done
  wait >/dev/null 2>&1 || true
  exit "${status}"
}

main() {
  require_command kubectl
  mkdir -p "${LOG_DIR}"

  trap cleanup INT TERM EXIT

  start_port_forward \
    devops \
    "${DEVOPS_CONTEXT}" \
    "${DEVOPS_NAMESPACE}" \
    "${DEVOPS_SERVICE}" \
    "${DEVOPS_LOCAL_PORT}" \
    "${DEVOPS_REMOTE_PORT}"

  start_port_forward \
    billing \
    "${BILLING_CONTEXT}" \
    "${BILLING_NAMESPACE}" \
    "${BILLING_SERVICE}" \
    "${BILLING_LOCAL_PORT}" \
    "${BILLING_REMOTE_PORT}"

  start_port_forward \
    account \
    "${ACCOUNT_CONTEXT}" \
    "${ACCOUNT_NAMESPACE}" \
    "${ACCOUNT_SERVICE}" \
    "${ACCOUNT_LOCAL_PORT}" \
    "${ACCOUNT_REMOTE_PORT}"

  start_port_forward \
    mgmt \
    "${MGMT_CONTEXT}" \
    "${MGMT_NAMESPACE}" \
    "${MGMT_SERVICE}" \
    "${MGMT_LOCAL_PORT}" \
    "${MGMT_REMOTE_PORT}"

  cat <<EOF

Local dependency port-forwards are ready.

Expected config.local.yaml values:
  devops.baseURL: http://127.0.0.1:${DEVOPS_LOCAL_PORT}
  billing.baseURL: http://127.0.0.1:${BILLING_LOCAL_PORT}
  account.grpcAddress: 127.0.0.1:${ACCOUNT_LOCAL_PORT}
  mgmt.grpcAddress: 127.0.0.1:${MGMT_LOCAL_PORT}

Logs:
  ${LOG_DIR}/devops.log
  ${LOG_DIR}/billing.log
  ${LOG_DIR}/account.log
  ${LOG_DIR}/mgmt.log

Press Ctrl-C to stop all port-forwards.
EOF

  wait
}

main "$@"
