#!/usr/bin/env bash
#
# Bagimli servisler hazir olana kadar bekler (OPS-5).
#
# ⛔ NEDEN VAR: her sey docker'da kosuyor ve `After=docker.service` yetmez.
# systemd icin "docker basladi" demek, daemon'un ayaga kalktigi andir; container'lar
# ondan SONRA, asenkron baslar. Yani reboot'ta Horizon, Redis'ten once ayaga
# kalkabilir ve `RedisException: Connection refused` ile calisir (OPS-2, OPS-3 —
# orada sebep deploy'du, ama ayni hata reboot'ta kimse basinda yokken de olur).
#
# ⚠ Systemd birimi bunu `ExecStartPre` olarak cagirir. Tek atislik bir kontrol
# yarisi tekrar ederdi; burada SUREYLE beklenir.
#
# ⛔ Bekleme DONGU ICINDE, birimin yeniden baslatmasinda degil. `Restart=always`
# ile hizli hizli dusen bir `ExecStartPre`, systemd'nin varsayilan start limitine
# (10 sn'de 5 deneme) carpar ve unit KALICI olarak vazgecer — korunmak istedigimiz
# hal, bu kez systemd eliyle. Birimlerde ayrica `StartLimitIntervalSec=0` var.
#
# Kullanim:
#   wait-for-services.sh redis postgres      # ikisini de bekle
#   WAIT_TIMEOUT=180 wait-for-services.sh redis
#
# Cikis: 0 hepsi hazir · 1 sure doldu · 2 kullanim hatasi
set -euo pipefail

TIMEOUT="${WAIT_TIMEOUT:-120}"
INTERVAL="${WAIT_INTERVAL:-2}"

ENV_FILE="${ENV_FILE:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)/.env}"

# ⚠ Portlar `.env`den okunur, burada YAZILMAZ. 11.08.2026'da portlar tasindi ve
# taşımayı atlayan her sabit deger sessizce yanlis yere baglandi (OPS-6).
value_of() {
    local key="$1" default="$2"

    if [[ -r "$ENV_FILE" ]]; then
        local found
        found="$(grep -E "^${key}=" "$ENV_FILE" | tail -1 | cut -d= -f2- | tr -d '"'"'"' \r' || true)"

        if [[ -n "$found" ]]; then
            echo "$found"

            return
        fi
    fi

    echo "$default"
}

# ⚠ Ciplak TCP degil, gercek bir cevap. Docker'in port proxy'si container hazir
# olmadan once de baglanti kabul edebilir; "port acik" ile "servis cevap veriyor"
# ayni sey degildir ve tam olarak bu fark yarisin kendisidir.
#
# ⛔ Sifreli Redis'te PING'e `NOAUTH` doner (EGT-267). Sifresiz PING atan bu kontrol
# sure dolana kadar bekler ve birim hic acilmaz — yani sifreyi koyan degisiklik
# kuyrugu durdururdu. Sifre `.env`den okunur ve komut satirina yazilmaz:
# redis-cli onu `REDISCLI_AUTH` ortam degiskeninden alir.
redis_ready() {
    local host="$1" port="$2"
    local password
    password="$(value_of REDIS_PASSWORD '')"

    if [[ "$password" == "null" ]]; then
        password=''
    fi

    if command -v redis-cli >/dev/null 2>&1; then
        local reply
        if [[ -n "$password" ]]; then
            reply="$(REDISCLI_AUTH="$password" redis-cli -h "$host" -p "$port" ping 2>/dev/null || true)"
        else
            reply="$(redis-cli -h "$host" -p "$port" ping 2>/dev/null || true)"
        fi

        [[ "$reply" == "PONG" ]]

        return
    fi

    # redis-cli yoksa protokolu elle konus: AUTH (varsa) ve PING'e +PONG doner.
    exec 3<>"/dev/tcp/${host}/${port}" 2>/dev/null || return 1

    if [[ -n "$password" ]]; then
        printf 'AUTH %s\r\n' "$password" >&3
    fi

    printf 'PING\r\n' >&3
    local reply ready=1
    while read -r -t 2 reply <&3; do
        if [[ "$reply" == "+PONG"* ]]; then
            ready=0

            break
        fi
    done
    exec 3<&- 3>&-

    return "$ready"
}

# ⚠ PostgreSQL'in kendisi degil, uygulamanin gectigi kapi (PgBouncer) beklenir —
# uygulama oraya baglanir. `pg_isready` her makinede kurulu degil; el sikismasinin
# ilk baytini beklemek yerine TCP yeterli, cunku pgbouncer portu ancak container
# ayaga kalkinca acilir.
tcp_ready() {
    local host="$1" port="$2"

    (exec 3<>"/dev/tcp/${host}/${port}") >/dev/null 2>&1
}

wait_for() {
    local label="$1" check="$2" host="$3" port="$4"
    local waited=0

    until "$check" "$host" "$port"; do
        if (( waited >= TIMEOUT )); then
            echo "wait-for-services: ${label} (${host}:${port}) ${TIMEOUT}s icinde hazir olmadi" >&2

            return 1
        fi

        sleep "$INTERVAL"
        waited=$(( waited + INTERVAL ))
    done

    echo "wait-for-services: ${label} hazir (${host}:${port}, ${waited}s)"
}

(( $# > 0 )) || { echo "kullanim: wait-for-services.sh <redis|postgres> [...]" >&2; exit 2; }

for service in "$@"; do
    case "$service" in
        redis)
            wait_for 'redis' redis_ready \
                "$(value_of REDIS_HOST 127.0.0.1)" "$(value_of REDIS_PORT 6379)"
            ;;
        postgres)
            wait_for 'postgres' tcp_ready \
                "$(value_of DB_HOST 127.0.0.1)" "$(value_of DB_PORT 5432)"
            ;;
        *)
            echo "wait-for-services: bilinmeyen servis '${service}'" >&2
            exit 2
            ;;
    esac
done
