#!/usr/bin/env bash
#
# Altyapiyi her ortamda AYNI sekilde ayaga kaldirir.
#
# Kural: dev = build = local prod = prod. Ayni compose dosyalari, ayni imajlar,
# ayni topoloji; ortamlar arasinda yalniz `.env` icindeki port ve kimlik
# degerleri farklidir. Boylece bir sorun nerede cikarsa ciksin her yerde ayni
# sekilde cikar.
#
# Bu script neden var: `docker compose -f deployment/...yml` cagrisinda Compose
# proje dizinini compose dosyasinin bulundugu dizin sayar ve `.env` dosyasini
# ORADA arar — yani `deployment/.env`. Depo kokundeki `.env` okunmaz ve
# `DB_PASSWORD is missing a value` hatasi alinir. Burada hem --env-file hem de
# --project-directory acikca depo koku olarak verilir.
#
# Kullanim:
#   deployment/scripts/stack.sh up            # postgresql + redis (+ varsa pgbouncer)
#   deployment/scripts/stack.sh up postgresql
#   deployment/scripts/stack.sh down
#   deployment/scripts/stack.sh status
#   deployment/scripts/stack.sh logs redis
#
#   STACK_ENV=prod deployment/scripts/stack.sh up    # Linux: redis host ag modu

set -euo pipefail

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

RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'; NC='\033[0m'

if [[ ! -f "${ENV_FILE}" ]]; then
    echo -e "${RED}✗ ${ENV_FILE} yok — once `cp .env.example .env` ve degerleri doldur.${NC}" >&2
    exit 1
fi

if ! command -v docker >/dev/null 2>&1; then
    export PATH="/Applications/Docker.app/Contents/Resources/bin:/opt/homebrew/bin:${PATH}"
fi

if ! docker info >/dev/null 2>&1; then
    echo -e "${RED}✗ Docker calismiyor.${NC}" >&2
    exit 1
fi

compose_files() {
    local requested="${1:-all}"
    local files=()

    if [[ "${requested}" == "all" || "${requested}" == "postgresql" ]]; then
        files+=(-f "${ROOT_DIR}/deployment/docker-compose.postgresql.yml")

        # ⛔ PRODUCTION OVERRIDE'I BURADAN YUKLENIR (09.08.2026).
        #
        # Dosya vardi, kimse yuklemiyordu: `STACK_ENV=prod` yalniz redis
        # override'ini ekliyordu ve postgresql/pgbouncer override'lari yalnizca
        # kendi baslik yorumlarindaki ELLE `docker compose -f ... -f ...`
        # komutuyla uygulanabiliyordu. Yani "veritabani portu internete acik kalmasin" diye
        # yazilmis dosya, kurulumu yapan hicbir yoldan gecmiyordu.
        #
        # ⚠ Bulundugu an: 10.31.1.210'a ilk gercek kurulum. Denetimin en
        # tehlikeli bulgusu icin yazilan duzeltmenin kendisi, cagrilmadigi icin
        # yururlukte degildi.
        if [[ "${STACK_ENV}" == "prod" ]]; then
            files+=(-f "${ROOT_DIR}/deployment/docker-compose.postgresql.prod.yml")
        fi
    fi

    if [[ "${requested}" == "all" || "${requested}" == "pgbouncer" ]]; then
        # PgBouncer tek basina istendiginde postgresql compose dosyasi da
        # yuklenir. Iki sebep: agi (3eegitim_network) o dosya tanimlar ve
        # PgBouncer'in `depends_on: postgresql` satiri onsuz cozulemez.
        #
        # Onceden yuklenmiyordu ve `stack.sh up pgbouncer` "undefined network"
        # diyip duruyordu — yani userlist duzeltildikten sonra PgBouncer'i
        # yeniden baslatmak icin README'de yazan komut calismiyordu
        # (27.07.2026, userlist eksikligi bulunurken ortaya cikti).
        if [[ "${requested}" == "pgbouncer" ]]; then
            files+=(-f "${ROOT_DIR}/deployment/docker-compose.postgresql.yml")

            if [[ "${STACK_ENV}" == "prod" ]]; then
                files+=(-f "${ROOT_DIR}/deployment/docker-compose.postgresql.prod.yml")
            fi
        fi

        # PgBouncer userlist'i sirlar icerir ve depoda durmaz. Yoksa PgBouncer
        # atlanir — bind mount bos dizin olusturup sessizce bozuk bir kurulum
        # birakmasin. Uygulama rolleri chunk2 ile geliyor.
        if [[ -f "${ROOT_DIR}/deployment/pgbouncer/userlist.txt" ]]; then
            files+=(-f "${ROOT_DIR}/deployment/docker-compose.pgbouncer.yml")

            # ⚠ Ayni sebep: prod override hem portu loopback'e ceker hem de
            # `pgbouncer.prod.ini`'yi (scram + kisitli listen_addr) baglar.
            if [[ "${STACK_ENV}" == "prod" ]]; then
                files+=(-f "${ROOT_DIR}/deployment/docker-compose.pgbouncer.prod.yml")
            fi
        elif [[ "${requested}" == "pgbouncer" ]]; then
            echo -e "${RED}✗ deployment/pgbouncer/userlist.txt yok.${NC}" >&2
            exit 1
        else
            echo -e "${YELLOW}⚠ userlist.txt yok — PgBouncer atlandi.${NC}" >&2
        fi
    fi

    if [[ "${requested}" == "all" || "${requested}" == "redis" ]]; then
        files+=(-f "${ROOT_DIR}/deployment/docker-compose.redis.yml")
        if [[ "${STACK_ENV}" == "prod" ]]; then
            files+=(-f "${ROOT_DIR}/deployment/docker-compose.redis.prod.yml")
        fi
    fi

    if [[ ${#files[@]} -eq 0 ]]; then
        echo -e "${RED}✗ Bilinmeyen servis: ${requested}${NC}" >&2
        exit 1
    fi

    printf '%s\n' "${files[@]}"
}

run_compose() {
    local requested="$1"; shift
    local files=()
    while IFS= read -r line; do files+=("${line}"); done < <(compose_files "${requested}")

    docker compose \
        --env-file "${ENV_FILE}" \
        --project-directory "${ROOT_DIR}" \
        "${files[@]}" "$@"
}

wait_for_postgres() {
    echo -e "${BLUE}→ PostgreSQL saglik kontrolu${NC}"
    for _ in $(seq 1 40); do
        local state
        state="$(docker inspect -f '{{.State.Health.Status}}' 3eegitim_postgresql 2>/dev/null || echo missing)"
        if [[ "${state}" == "healthy" ]]; then
            echo -e "${GREEN}✓ PostgreSQL hazir${NC}"
            return 0
        fi
        sleep 3
    done
    # Sebebi goster. Ciplak bir zaman asimi, tanisi olmayan bir hatadir:
    # PG18'e gecerken CI tam olarak burada iki dakika sessizce bekleyip
    # "saglikli duruma gelmedi" dedi, oysa container her denemede
    # "database files are incompatible with server" yaziyordu (26.07.2026).
    echo -e "${RED}✗ PostgreSQL saglikli duruma gelmedi${NC}" >&2
    echo -e "${YELLOW}--- container loglari (son 20 satir) ---${NC}" >&2
    docker logs 3eegitim_postgresql 2>&1 | tail -20 >&2

    if docker logs 3eegitim_postgresql 2>&1 | grep -q "database files are incompatible with server"; then
        echo >&2
        echo -e "${RED}Veri dizini baska bir PostgreSQL major surumu tarafindan olusturulmus.${NC}" >&2
        echo -e "${YELLOW}Major yukseltmede veri dizini TASINMAZ. Dev/CI ortamlarinda volume silinir${NC}" >&2
        echo -e "${YELLOW}ve migration'lar yeniden kosar:${NC}" >&2
        echo >&2
        echo -e "    docker rm -f 3eegitim_postgresql && docker volume rm 3eegitim_postgres_data" >&2
        echo -e "    ./deployment/scripts/stack.sh up postgresql" >&2
        echo >&2
        echo -e "${RED}PRODUCTION'DA BU KOMUTLARI CALISTIRMA${NC} — orasi bir pg_upgrade isidir (EGT-51)." >&2
    fi

    return 1
}

# ⛔ Alt agi degismis bir ag KENDILIGINDEN yeniden yaratilamaz (09.08.2026).
#
# PgBouncer'in PostgreSQL'e sabit adresten bagilanabilmesi icin
# `3eegitim_network` artik acik bir alt ag tasiyor. Docker var olan bir agin
# ayarlarini degistirmez; compose onu silmeyi dener ve **bagli container varsa
# duser**. CI'da tam bu oldu: redis dugumleri bridge modunda ayni aga bagliydi,
# hata "network has active endpoints" diye cikti ve build kirmizi dondu.
#
# ⚠ Silmeyi bu script YAPMAZ. Ag silmek calisan her seyi durdurmayi gerektirir
# ve bunun ne zaman olacagina operator karar verir; burada yalnizca teshis ve
# komut vardir.
NETWORK_SUBNET="172.29.0.0/24"

check_network_subnet() {
    local current
    current="$(docker network inspect 3eegitim_network -f '{{range .IPAM.Config}}{{.Subnet}}{{end}}' 2>/dev/null || true)"

    [[ -n "${current}" && "${current}" != "${NETWORK_SUBNET}" ]] || return 0

    echo -e "${RED}✗ 3eegitim_network ${current} uzerinde — beklenen ${NETWORK_SUBNET}${NC}" >&2
    echo -e "${YELLOW}  Sabit adresler (pgbouncer → postgresql) ancak dogru alt agda calisir.${NC}" >&2
    echo -e "${YELLOW}  Ag bir kez elle yeniden yaratilir:${NC}" >&2
    echo >&2
    echo -e "    ./deployment/scripts/stack.sh down" >&2
    echo -e "    docker network rm 3eegitim_network" >&2
    echo -e "    ./deployment/scripts/stack.sh up" >&2
    echo >&2
    echo -e "${YELLOW}  Veri kaybi yok: volume'lara dokunulmuyor.${NC}" >&2

    exit 1
}

command="${1:-status}"
service="${2:-all}"

case "${command}" in
    up)
        check_network_subnet

        # Imaj depoda tanimli Dockerfile'dan uretilir; hazir imaj cekilmez.
        # shared_preload_libraries'te anon ZORUNLU oldugu icin ozel imaj sart.
        if [[ "${service}" == "all" || "${service}" == "postgresql" ]]; then
            echo -e "${BLUE}→ PostgreSQL imaji${NC}"
            docker build -q -t 3eegitim/postgresql:18-custom "${ROOT_DIR}/deployment/postgresql" >/dev/null
        fi
        run_compose "${service}" up -d
        if [[ "${service}" == "all" || "${service}" == "postgresql" ]]; then
            wait_for_postgres

            # Test veritabanini da kur — AMA yalnizca bu makine test kosuyorsa.
            # Kosul `.env.testing`in varligi: o dosya bir gelistirme/CI
            # artefaktidir, production'da bulunmaz (depoda yalnizca
            # `.env.testing.example` var). Boylece production'da test rolu veya
            # test veritabani YARATILMAZ.
            #
            # Gerekce (26.07.2026): PG18 yukseltmesinde cluster sifirdan
            # kuruldu ve CI 13 testle dustu — test rolu ve veritabani yoktu,
            # cunku kurulum script'i yalnizca elle kosuluyordu. CI pest'i
            # dogrudan cagiriyor, `composer test` uzerinden degil; dolayisiyla
            # composer tarafindaki kurulum adimi CI'a ulasmiyor. Kendi
            # veritabanini kuramayan bir build, ortam her yenilendiginde kirilir.
            if [[ -f "${ROOT_DIR}/.env.testing" ]]; then
                "${ROOT_DIR}/deployment/scripts/setup-test-database.sh"
            fi
        fi
        run_compose "${service}" ps
        ;;
    down)
        # Volume'lar korunur: `down -v` veri kaybidir, acikca istenmelidir.
        run_compose "${service}" down
        ;;
    status)
        run_compose "${service}" ps
        ;;
    logs)
        run_compose "${service}" logs --tail 100 -f
        ;;
    *)
        echo "Kullanim: $0 {up|down|status|logs} [postgresql|pgbouncer|redis|all]" >&2
        exit 1
        ;;
esac
