#!/bin/bash

# Forward local ports to production redis + postgres via kubernetes

set -euo pipefail

START_TIMEOUT=15
MONITOR_TIMEOUT=5

function die() {
  echo "$@" >&2
  exit 1
}

function set_traps() {
  trap 'trap - EXIT && trap exit SIGTERM && kill 0' SIGINT SIGTERM EXIT
}

function forward_redis {
  redis_auth=$(
    kubectl get secret -n=redis \
      prod-redis \
      -o jsonpath='{.data.redis-password}' \
      | base64 -d
  )

  [ -n "$redis_auth" ] || die "Failed to retrieve redis password from secret"

  redis_pods=$(
    kubectl get pod -n=redis \
      -o jsonpath="{range.items[*]}{..metadata.name}{'\n'}{end}" \
      --field-selector=status.phase=Running
  )

  for pod in $redis_pods; do
    kubectl exec -n=redis -i $pod -c redis -- \
      redis-cli --pass "$redis_auth" set testkey 1 \
      | grep -q READONLY || break
  done

  [ -n "$pod" ] || die "No master pod found"

  exec kubectl port-forward -n=redis pod/$pod 6379
}

function check_redis {
  redis-cli PING | grep -q NOAUTH
}

function forward_postgres {
  exec kubectl port-forward -n=production svc/postgres-proxy 5433:5432
}

function check_postgres {
  pg_isready -h localhost -p 5433 >/dev/null
}

function my_timeout {
  (
    set +e
    timeout="$1"
    shift
    "$@" & childpid=$!
    ( sleep $timeout ; kill -9 $childpid 2>/dev/null ) & sleeperpid=$!
    wait $childpid 2>/dev/null
    ret=$?
    kill $sleeperpid 2>/dev/null
    exit $ret
  )
}

function monitor_loop {
  worker="$1"
  monitor="$2"

  $worker &

  start_time="$(date +%s)"
  ready=""

  while true; do
    sleep 10
    if my_timeout $MONITOR_TIMEOUT $monitor; then
      ready=yes
      continue
    fi

    if [ -z "$ready" ]; then
      current_time="$(date +%s)"
      if (( current_time - start_time > START_TIMEOUT )); then
        echo "$worker failed to pass $monitor within $START_TIMEOUT seconds of start" >&2
        break
      fi
    else
      echo "$worker transitioned from passing to failing $monitor" >&2
      break
    fi
  done
}

function restart_loop_bg {
  (
    while true; do
      set -m
      monitor_loop "$@" & pgid=$!
      set +m
      trap "kill -9 -$pgid" SIGINT SIGTERM EXIT
      wait $pgid
    done
  ) &
}

function forward_fusion_auth {
  SVC_NAME=$(kubectl get svc --namespace fusionauth -l "app.kubernetes.io/name=fusionauth,app.kubernetes.io/instance=wavtool-idp" -o jsonpath="{.items[0].metadata.name}")
  kubectl port-forward --namespace fusionauth svc/$SVC_NAME 9011:9011
}

set_traps
restart_loop_bg forward_redis check_redis
restart_loop_bg forward_postgres check_postgres
forward_fusion_auth &
wait
