#!/usr/bin/env bash
# 192.168.0.188 主機層 momo PostgreSQL 備份控制器。
#
# 由 Ansible 部署到：
#   /home/ollama/momo-pro/scripts/pg_backup.sh
#
# PostgreSQL 憑證只從 momo-db 容器環境讀取；禁止輸出或落地憑證值。

set -Eeuo pipefail

BACKUP_DIR="${BACKUP_DIR:-/home/ollama/momo_backups}"
DB_CONTAINER="${DB_CONTAINER:-momo-db}"
DB_USER="${DB_USER:-momo}"
DB_NAME="${DB_NAME:-momo_analytics}"
KEEP_DAYS="${KEEP_DAYS:-7}"
MIN_SIZE_BYTES="${MIN_SIZE_BYTES:-1048576}"
LOG_FILE="${LOG_FILE:-${BACKUP_DIR}/backup.log}"
TIMESTAMP="$(date +%Y%m%d_%H%M%S)"
FILENAME="momo_analytics_${TIMESTAMP}.sql.gz"
FILEPATH="${BACKUP_DIR}/${FILENAME}"
TMP_FILE="${FILEPATH}.tmp"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
START_TS="$(date +%s)"

log() {
    local line
    line="$(printf '[%s] %s' "$(date '+%Y-%m-%d %H:%M:%S')" "$*")"
    printf '%s\n' "$line" >> "${LOG_FILE}"
    if [[ "${AWOOI_BACKUP_LOG_STDOUT:-0}" == "1" || -t 1 ]]; then
        printf '%s\n' "$line"
    fi
}

cleanup_tmp() {
    rm -f "${TMP_FILE}"
}

elapsed_seconds() {
    local now
    now="$(date +%s)"
    echo "$((now - START_TS))"
}

notify_awoooi_ops() {
    local status="$1"
    local summary="$2"
    local detail="$3"
    local helper="${SCRIPT_DIR}/notify-awoooi-ops.sh"

    if [[ "${AWOOI_BACKUP_NOTIFY_ENABLED:-1}" != "1" ]]; then
        return 0
    fi
    [[ -x "$helper" ]] || return 1

    AWOOI_OPS_ALERTNAME="Backup.MomoPostgres" \
    AWOOI_OPS_JOB_NAME="MOMO PostgreSQL 備份" \
    AWOOI_OPS_STATUS="$status" \
    AWOOI_OPS_SEVERITY="info" \
    AWOOI_OPS_SOURCE="momo-pg-backup" \
    AWOOI_OPS_COMPONENT="momo-postgres-backup" \
    AWOOI_OPS_SUMMARY="$summary" \
    AWOOI_OPS_DETAIL="$detail" \
    AWOOI_OPS_DURATION_SECONDS="$(elapsed_seconds)" \
    "$helper" >/dev/null
}

notify_best_effort() {
    local status="$1"
    local summary="$2"
    local detail="$3"
    if [[ "$status" == "success" && "${AWOOI_BACKUP_NOTIFY_SUCCESS:-0}" != "1" ]]; then
        log "略過 AwoooP 成功通知；backup-health exporter 作為健康狀態來源"
        return 0
    fi
    notify_awoooi_ops "$status" "$summary" "$detail" || log "WARN AwoooP notification failed"
}

on_error() {
    local exit_code="$?"
    local line_no="${1:-unknown}"
    set +e
    notify_awoooi_ops \
        "failed" \
        "MOMO PostgreSQL 備份失敗" \
        "line=${line_no}; container=${DB_CONTAINER}; db=${DB_NAME}; file=${FILENAME}; log=${LOG_FILE}" \
        || true
    exit "$exit_code"
}

fail_backup() {
    local message="$1"
    log "ERROR ${message}"
    notify_awoooi_ops \
        "failed" \
        "MOMO PostgreSQL 備份失敗" \
        "${message}; container=${DB_CONTAINER}; db=${DB_NAME}; file=${FILENAME}; log=${LOG_FILE}" \
        || true
    exit 1
}

container_running() {
    docker inspect -f '{{.State.Running}}' "${DB_CONTAINER}" 2>/dev/null | grep -qx true
}

run_pg_dump() {
    docker exec "${DB_CONTAINER}" sh -eu -c '
        : "${POSTGRES_PASSWORD:?POSTGRES_PASSWORD missing in container env}"
        PGPASSWORD="${POSTGRES_PASSWORD}" exec pg_dump \
            -U "${POSTGRES_USER:-momo}" \
            -d "${POSTGRES_DB:-momo_analytics}" \
            --no-password \
            --no-owner \
            --no-acl
    '
}

insert_backup_log() {
    local size_bytes="$1"
    local duration="$2"
    docker exec \
        -e BACKUP_FILENAME="${FILENAME}" \
        -e BACKUP_SIZE_BYTES="${size_bytes}" \
        -e BACKUP_DURATION_SECONDS="${duration}" \
        -e BACKUP_HOST="$(hostname)" \
        -e BACKUP_STORAGE_PATH="${FILEPATH}" \
        "${DB_CONTAINER}" sh -eu -c '
            : "${POSTGRES_PASSWORD:?POSTGRES_PASSWORD missing in container env}"
            PGPASSWORD="${POSTGRES_PASSWORD}" psql \
                -U "${POSTGRES_USER:-momo}" \
                -d "${POSTGRES_DB:-momo_analytics}" \
                --no-password \
                -v ON_ERROR_STOP=1 \
                -c "INSERT INTO backup_log (filename, file_size_bytes, duration_seconds, status, host, storage_path, completed_at)
                    VALUES (E'\''${BACKUP_FILENAME}'\'', ${BACKUP_SIZE_BYTES}, ${BACKUP_DURATION_SECONDS}, '\''success'\'', E'\''${BACKUP_HOST}'\'', E'\''${BACKUP_STORAGE_PATH}'\'', CURRENT_TIMESTAMP);"
        ' >/dev/null 2>&1
}

main() {
    mkdir -p "${BACKUP_DIR}"
    trap cleanup_tmp EXIT
    trap 'on_error ${LINENO}' ERR

    log "===== momo PostgreSQL backup start ====="
    if ! container_running; then
        fail_backup "${DB_CONTAINER} is not running"
    fi

    local start_ts end_ts duration size_bytes size_human deleted backup_log_status
    start_ts="$(date +%s)"
    if run_pg_dump | gzip >"${TMP_FILE}"; then
        size_bytes="$(stat -c%s "${TMP_FILE}" 2>/dev/null || stat -f%z "${TMP_FILE}" 2>/dev/null || echo 0)"
        if [ "${size_bytes}" -lt "${MIN_SIZE_BYTES}" ]; then
            fail_backup "backup file too small: ${size_bytes} bytes"
        fi
        mv "${TMP_FILE}" "${FILEPATH}"
        chmod 0640 "${FILEPATH}"
    else
        fail_backup "pg_dump failed"
    fi

    end_ts="$(date +%s)"
    duration="$((end_ts - start_ts))"
    size_human="$(du -h "${FILEPATH}" | awk '{print $1}')"
    log "Backup success: ${FILENAME} (${size_human}, ${duration}s)"

    backup_log_status="success"
    if insert_backup_log "${size_bytes}" "${duration}"; then
        log "backup_log insert success"
    else
        backup_log_status="warning"
        log "WARN backup_log insert failed; backup file is still valid"
    fi

    deleted="$(find "${BACKUP_DIR}" -name 'momo_analytics_*.sql.gz' -mtime "+${KEEP_DAYS}" -print -delete | wc -l | tr -d ' ')"
    log "Deleted old backups: ${deleted}"
    log "===== momo PostgreSQL backup complete ====="

    notify_best_effort \
        "success" \
        "MOMO PostgreSQL 備份完成" \
        "file=${FILENAME}; size=${size_human}; duration=${duration}s; backup_log=${backup_log_status}; deleted_old=${deleted}"
}

main "$@"
