#!/bin/bash
#
# Kurulum on kosullari (plan chunk9 §9.6, EGT-34 kriter 9).
#
# ── Neden bir metin degil, kosan bir kontrol ────────────────────────────────
#
# Sets, 07.08.2026: *"o tarz bir metin yerine gercekten aktif calisan bir
# kontrol cok daha saglikli olur, deploy oncesinde kosar ve dogrulama yapar."*
#
# ⛔ Buradaki maddelerin ortak ozelligi: atlandiklarinda sistem SESSIZCE degil,
# ama SEBEBI GORUNMEYECEK sekilde bozulur. "Veritabanina baglanamiyor" hatasi
# eksik bir pgbouncer rolunu gostermez; kodda aranir. Bu script o teshisi
# onceden yapar ve ne yapilacagini soyler.
#
# ── Kullanim ───────────────────────────────────────────────────────────────
#
#   deployment/scripts/preflight.sh          # kontrol et, eksikte cik
#   PREFLIGHT_SKIP=1 deployment/scripts/...  # bilerek atla (deploy.sh okur)
#
# `deploy.sh` bunu en basta kendi cagirir; ayrica elle de kosulabilir.
#
set -uo pipefail

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

# ⛔ USERLIST DEPODA DEGIL, olamaz da: parola tasir ve gitignore'dadir. Bu
# script bir RELEASE dizininden kosuldugunda `${ROOT}/deployment/...` her zaman
# BOSTUR — yani kontrol her deploy'da duserdi ve 09.08.2026'da tam olarak oyle
# oldu: deploy `PREFLIGHT_SKIP=1` ile gecildi. HER ZAMAN ATLANAN BIR KONTROL,
# OLMAYANDAN KOTUDUR; atlamayi ogretir ve yanindaki gercek bulgular da atlanir.
#
# ⚠ Dosyanin gercek yeri sunucuda `shared/infra/...` altidir ve pgbouncer
# konteynerine oradan baglanir (olculdu, 10.08.2026). Aday listesi sirayla
# denenir; hicbiri yoksa bulunamadi denir.
find_userlist() {
    local candidate
    for candidate in \
        "${ROOT}/deployment/pgbouncer/userlist.txt" \
        "${ROOT}/../../shared/infra/deployment/pgbouncer/userlist.txt" \
        "${ROOT}/../shared/infra/deployment/pgbouncer/userlist.txt"
    do
        [[ -f "$candidate" ]] && { printf '%s' "$candidate"; return; }
    done

    printf '%s' "${ROOT}/deployment/pgbouncer/userlist.txt"
}

USERLIST="${USERLIST:-$(find_userlist)}"

FAILED=0

ok()   { printf '\033[1;32m✓\033[0m %s\n' "$1"; }
bad()  { printf '\033[1;31m✗\033[0m %s\n' "$1"; FAILED=1; }
hint() { printf '  \033[2m→ %s\033[0m\n' "$1"; }
note() { printf '\033[1;33m⚠\033[0m %s\n' "$1"; }

# `.env` degerini okur. grep ^ANCHOR'li: `APP_KEY` ararken `TENANT_ROOT_KEY`
# satirini yakalamamak icin (teamcity.sh ayni tuzaga dusmustu).
envval() {
    [[ -f "$ENV_FILE" ]] || return 0
    grep "^${1}=" "$ENV_FILE" | head -1 | cut -d= -f2- | tr -d '"' | tr -d "'"
}

printf '\033[1;36m→\033[0m Kurulum on kosullari\n'

# ── 0 ──────────────────────────────────────────────────────────────────────
#
# ⛔ HANGI PHP (10.08.2026, Hetzner'de olculdu). `/usr/bin/php` orada 8.3.32,
# uygulama 8.4.1 istiyor, nginx zaten php8.5-fpm'e bagli — yani site dogru
# calisirken KABUKTAKI varsayilan yanlisti. Ciplak `php` ile kosan bir deploy
# composer adiminda duser; daha kotusu, dusmeyip yanlis surum icin cozerse
# uygulama deploy "basarili" dedikten sonra ilk istekte patlar.
#
# ⛔ SURUM TAHMIN EDILMEZ, BILDIRILIR (Sets, 11.08.2026: "8.5 projenin php
# surumu, buna gore calissin — statik olarak 8.5 girmeliyiz"). Yorumlayiciyi
# secen tek yer `php-bin.sh` ve okudugu tek sey `.php-version`. Bu script eskiden
# ciplak `php`ye dusuyordu, `deploy.sh` ise "kurulu olanlarin en yenisi"ni
# ariyordu: iki cevap, ve 11.08'de bir deploy tam bu ayrisma yuzunden durdu —
# deploy dogru yorumlayiciyi bulmus, kendi on kosul kontrolu 8.3'e bakip
# "karsilanmiyor" demisti.
#
# ⚠ Bildirim uc yerde ayni: `.php-version`, `composer.json` (`require.php` ve
# `config.platform.php`) ve nginx'in bagli oldugu `php8.5-fpm`.
#
# ⚠ Kisit BURADA COZULMEZ, composer'a sorulur: gercek taban bir bagimliliktan
# gelebilir ve lock satirlarini elle ayristirmak yanlis cevap uretir (denendi).
# Soruyu sahibi cevaplar: `check-platform-reqs --lock`.
#
# ⚠ `--lock`: vendor/ kurulu olmadan da cevap verir, yani ILK kurulumda da
# calisir — ki bu script'in var olma sebebi tam olarak ilk kurulumdur.
# shellcheck source=deployment/scripts/php-bin.sh
. "$(dirname "${BASH_SOURCE[0]}")/php-bin.sh"

php_version="$("$PHP_BIN" -r 'echo PHP_VERSION;' 2>/dev/null || echo '?')"

if "${COMPOSER_CMD[@]}" check-platform-reqs --lock --working-dir="$ROOT" >/dev/null 2>&1; then
    ok "PHP ${php_version} (${PHP_BIN}) — platform gereksinimleri karsilaniyor"
else
    bad "PHP ${php_version} (${PHP_BIN}) uygulamanin istedigini karsilamiyor"
    "${COMPOSER_CMD[@]}" check-platform-reqs --lock --working-dir="$ROOT" 2>&1 | grep -vi success | head -5
    hint "Proje .php-version ile PHP ${PHP_WANTED} istiyor; composer.json da ayni surumu bildirir."
fi

# ── 1 ──────────────────────────────────────────────────────────────────────
#
# ⛔ Iki rol de userlist'te olmali. Eksikse uygulama veritabanina HIC
# baglanamaz ve hata kimlik dogrulama hatasi olarak cikar — sebebi gorunmez.
# Mali rol ayri: muhasebe baglantisi kendi rolunu kullanir.
if [[ ! -f "$USERLIST" ]]; then
    bad "pgbouncer/userlist.txt yok"
    hint "userlist.txt.example kopyalanip parolalar yazilmali"
else
    for role in 3eegitim_app 3eegitim_app_financial; do
        if grep -q "\"${role}\"" "$USERLIST"; then
            ok "pgbouncer userlist: ${role}"
        else
            bad "pgbouncer userlist'te ${role} yok"
            hint "Rolu ekleyip pgbouncer'i yeniden baslatin; yoksa uygulama baglanamaz"
        fi
    done
fi

# ── 2 ──────────────────────────────────────────────────────────────────────
#
# ⛔ Tenant anahtari uygulama anahtarindan TUREMEZ. Ayni olsalardi bir
# APP_KEY rotasyonu her tenant'in sifreli verisini okunamaz hale getirirdi
# (AD-05).
APP_KEY="$(envval APP_KEY)"
TENANT_KEY="$(envval TENANT_ROOT_KEY)"

if [[ -z "$TENANT_KEY" ]]; then
    bad "TENANT_ROOT_KEY tanimli degil"
    hint "php artisan key:generate --show ile uretip .env'e yazin (APP_KEY ile AYNI OLMAYACAK)"
elif [[ "$TENANT_KEY" == "$APP_KEY" ]]; then
    bad "TENANT_ROOT_KEY, APP_KEY ile ayni"
    hint "Ayri bir anahtar uretin: APP_KEY rotasyonu tenant verisini okunamaz birakmamali"
else
    ok "TENANT_ROOT_KEY tanimli ve APP_KEY'den farkli"
fi

# ── 3 ──────────────────────────────────────────────────────────────────────
#
# ⚠ Yalniz uzak disk kullaniliyorsa sorulur. Bugun DOCUMENT_DISK=local
# (Sets, 05.08.2026: ilk fazda yerel sifreli disk, production dahil) ve o
# durumda public bucket diye bir sey yoktur.
DISK="$(envval DOCUMENT_DISK)"

if [[ "$DISK" == "local" || -z "$DISK" ]]; then
    ok "Belge diski yerel — public bucket kontrolu konusuz"
else
    note "Belge diski '${DISK}' — bucket'ta public erisimin KAPALI oldugu elle dogrulanmali"
    hint "Public bir bucket, imzali baglantiyi anlamsiz kilar (AD-16)"
fi

# ── 4 ──────────────────────────────────────────────────────────────────────
#
# ⛔ HICBIR LOG OTOMATIK SILINMEZ (Sets, 07.08.2026). Saklama yukumlulugu 10
# yila kadar uzuyor; hangi logun hangi yukumluluge cevap verdigi yillar sonra
# sorulan bir soru ve dusen bir chunk geri getirilemez.
#
# ⚠ Bu kontrol suitede de var (`AuditSchemaTest`), ama suite REPODAKI semayi
# okur — burada sorulan sey CANLI VERITABANININ zamanlayicisi. Elle psql'den
# eklenen bir policy repoda hicbir iz birakmaz; zaten 07.08.2026'da bulunan da
# koddan degil, veritabanina sorulunca cikti.
#
# ⚠ Baglanti kurulamiyorsa ya da TimescaleDB yoksa UYARI verir, dusmez: ilk
# kurulumda veritabani henuz yoktur ve on kosul kontrolu ilk kurulumu
# engellememeli.
DB_HOST_VALUE="$(envval DB_HOST)"
DB_PORT_VALUE="$(envval DB_DIRECT_PORT)"
DB_NAME_VALUE="$(envval DB_DATABASE)"
DB_ADMIN_USER="$(envval DB_ADMIN_USERNAME)"
DB_ADMIN_PASS="$(envval DB_ADMIN_PASSWORD)"

retention_jobs() {
    PGPASSWORD="$DB_ADMIN_PASS" psql \
        --host "${DB_HOST_VALUE:-127.0.0.1}" --port "${DB_PORT_VALUE:-5432}" \
        --username "${DB_ADMIN_USER:-postgres}" --dbname "$DB_NAME_VALUE" \
        --no-align --tuples-only --quiet \
        --command "SELECT count(*) FROM timescaledb_information.jobs WHERE proc_name = 'policy_retention'" \
        2>/dev/null
}

if ! command -v psql >/dev/null 2>&1; then
    note "psql yok — otomatik silme kontrolu yapilamadi"
    hint "Kontrol suitede de var; yine de kurulum sunucusunda psql bulunmali"
elif [[ -z "$DB_NAME_VALUE" ]]; then
    note "DB_DATABASE bos — otomatik silme kontrolu yapilamadi"
else
    JOBS="$(retention_jobs)"

    if [[ -z "$JOBS" ]]; then
        note "Veritabanina baglanilamadi ya da TimescaleDB yok — otomatik silme kontrolu atlandi"
        hint "Ilk kurulumda beklenir; mevcut bir kurulumda bu bir bulgudur"
    elif [[ "$JOBS" == "0" ]]; then
        ok "Otomatik silen retention job yok"
    else
        bad "Veritabaninda ${JOBS} adet retention job KOSUYOR"
        hint "SELECT hypertable_name, config FROM timescaledb_information.jobs WHERE proc_name='policy_retention'"
        hint "Kaldirin: SELECT remove_retention_policy('<tablo>', if_exists => true)"
    fi
fi

# ── Kapsam disi birakilan madde ────────────────────────────────────────────
#
# ⚠ Planin 4. on kosulu — "TreeScopeResolver devreye girmeden gercek musteri
# verisi yuklenmez" — BURADA YOK, cunku gerekcesi ortadan kalkti (07.08.2026).
# Kisit "ofis kimligi hicbir tenant'a cozulmuyor" olgusuna dayaniyordu; §6.5.2
# ayni gun izin + atama desenini kurdu ve ofis kapsami calisiyor. Eksik olan
# grup agacidir (Spec 3 / EGT-23) ve o bir prod cikis engeli degil.

echo
if [[ $FAILED -eq 1 ]]; then
    printf '\033[1;31m✗ On kosullar saglanmadi — kurulum durduruldu.\033[0m\n'
    exit 1
fi

printf '\033[1;32m✓ On kosullar saglandi.\033[0m\n'
