#!/usr/bin/env bash
# deploy.sh — deployment dengan release folder, symlink current, dan
# health check.
#
# Alur satu eksekusi:
#   1. baca dan validasi konfigurasi (deploy.conf)
#   2. validasi artifact build (index.html wajib ada)
#   3. salin build ke releases/STAMP lalu verifikasi salinannya
#   4. geser symlink current ke release baru
#   5. health check dengan retry; gagal -> rollback otomatis ke
#      release sebelumnya dan release baru dihapus
#
# Variabel lingkungan (per eksekusi):
#   CONF       berkas konfigurasi yang dibaca (default: deploy.conf)
#   BUILD_DIR  folder artifact yang dideploy (default: build)
#   STAMP      identitas release (default: waktu sekarang, YYYYmmdd-HHMMSS)
#
# Kode keluar:
#   0 sukses                          1 konfigurasi tidak valid
#   2 artifact build tidak siap       3 release gagal disalin/diverifikasi
#   4 health check gagal (current sudah dikembalikan ke release lama)

set -u

CONF="${CONF:-deploy.conf}"
BUILD_DIR="${BUILD_DIR:-build}"
STAMP="${STAMP:-$(date +%Y%m%d-%H%M%S)}"

# log(): tulis satu baris beridentitas release ke stdout.
log() {
    printf '[%s] %s\n' "$STAMP" "$1"
}

# die(): catat kegagalan lewat log, lalu keluar dengan kode tertentu.
die() {
    log "GAGAL: $1 (kode $2)"
    exit "$2"
}

# --- 1. Baca dan validasi konfigurasi ---------------------------------
# Pesan tahap ini keluar lewat stderr: gagal di sini berarti skrip
# belum boleh menyentuh folder site sama sekali.
if [ ! -f "$CONF" ]; then
    printf 'deploy.sh: berkas konfigurasi %s tidak ditemukan\n' "$CONF" >&2
    exit 1
fi

# shellcheck source=/dev/null
. "$CONF"

if [ -z "${SITE_DIR:-}" ]; then
    printf 'deploy.sh: SITE_DIR belum diisi di %s\n' "$CONF" >&2
    exit 1
fi
if [ -z "${HEALTH_URL:-}" ]; then
    printf 'deploy.sh: HEALTH_URL belum diisi di %s\n' "$CONF" >&2
    exit 1
fi
case ${HEALTH_RETRIES:-} in
    ''|*[!0-9]*|0)
        printf 'deploy.sh: HEALTH_RETRIES harus angka 1 atau lebih\n' >&2
        exit 1
        ;;
esac
case ${HEALTH_DELAY:-} in
    ''|*[!0-9]*)
        printf 'deploy.sh: HEALTH_DELAY harus angka 0 atau lebih\n' >&2
        exit 1
        ;;
esac

# --- 2. Validasi artifact build ----------------------------------------
[ -d "$BUILD_DIR" ] || die "folder build tidak ditemukan: $BUILD_DIR" 2
[ -f "$BUILD_DIR/index.html" ] || die "index.html tidak ada di $BUILD_DIR" 2

# --- 3. Siapkan struktur site dan release baru -------------------------
mkdir -p "$SITE_DIR/releases" || exit 1
RELEASE="$SITE_DIR/releases/$STAMP"
if [ -e "$RELEASE" ]; then
    die "release $STAMP sudah ada; pakai STAMP yang berbeda" 1
fi

# Target symlink saat ini disimpan dulu: inilah tujuan rollback bila
# health check release baru gagal.
PREV=""
if [ -L "$SITE_DIR/current" ]; then
    PREV=$(readlink "$SITE_DIR/current")
fi

# --- 4. Salin artifact lalu verifikasi salinannya -----------------------
if ! cp -a "$BUILD_DIR" "$RELEASE"; then
    die "gagal menyalin $BUILD_DIR ke $RELEASE" 3
fi
if ! diff -r "$BUILD_DIR" "$RELEASE" > /dev/null; then
    rm -rf "$RELEASE"
    die "salinan release berbeda dari build" 3
fi
log "release tersalin: $RELEASE"

# --- 5. Geser symlink current ke release baru ---------------------------
# Target dibuat relatif terhadap folder site supaya struktur bisa
# dipindahkan tanpa memutus tautan.
ln -sfn "releases/$STAMP" "$SITE_DIR/current"
log "current -> releases/$STAMP"

# --- 6. Health check dengan retry ---------------------------------------
sehat=0
for percobaan in $(seq 1 "$HEALTH_RETRIES"); do
    if curl -fsS -o /dev/null "$HEALTH_URL" 2> /dev/null; then
        sehat=1
        break
    fi
    sleep "$HEALTH_DELAY"
done

if [ "$sehat" -ne 0 ]; then
    log "health check OK: $HEALTH_URL"
    log "selesai tanpa error"
    exit 0
fi

# --- 7. Health check gagal: rollback otomatis ---------------------------
# Release yang tidak sehat dihapus supaya rollback di masa depan
# tidak pernah mendarat di release rusak.
if [ -n "$PREV" ]; then
    ln -sfn "$PREV" "$SITE_DIR/current"
    log "health check gagal; current dikembalikan ke $PREV"
else
    rm -f "$SITE_DIR/current"
    log "health check gagal; tidak ada release sebelumnya; current dihapus"
fi
rm -rf "$RELEASE"
die "health check gagal setelah $HEALTH_RETRIES percobaan: $HEALTH_URL" 4
