#!/usr/bin/env bash
set -euo pipefail

BACKUP_DIR="${BACKUP_DIR:-/tmp/raseel-backups}"
LOG_FILE="${LOG_FILE:-storage/logs/backup.log}"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_NAME="raseel_${TIMESTAMP}"
BACKUP_FILE="${BACKUP_DIR}/${BACKUP_NAME}.sql.gz.enc"
RETENTION_DAILY=7
RETENTION_WEEKLY=4
RETENTION_MONTHLY=12

mkdir -p "$BACKUP_DIR"
mkdir -p "$(dirname "$LOG_FILE")"

log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}

cleanup() {
    EXIT_CODE=$?
    if [ $EXIT_CODE -ne 0 ]; then
        log "Backup failed with exit code ${EXIT_CODE}"
    fi
    rm -f "${BACKUP_DIR}/${BACKUP_NAME}.sql.gz" 2>/dev/null || true
    exit $EXIT_CODE
}

trap cleanup EXIT

check_env() {
    local missing=0
    for var in DB_HOST DB_PORT DB_DATABASE DB_USERNAME DB_PASSWORD BACKUP_ENCRYPTION_PASSWORD AWS_BUCKET AWS_DEFAULT_REGION; do
        if [ -z "${!var:-}" ]; then
            log "ERROR: Missing environment variable: ${var}"
            missing=1
        fi
    done
    if [ -z "${AWS_ACCESS_KEY_ID:-}" ] || [ -z "${AWS_SECRET_ACCESS_KEY:-}" ]; then
        log "ERROR: Missing AWS credentials"
        missing=1
    fi
    return $missing
}

dump_database() {
    log "Dumping database ${DB_DATABASE} from ${DB_HOST}:${DB_PORT}"
    PGPASSWORD="$DB_PASSWORD" pg_dump \
        --host="$DB_HOST" \
        --port="$DB_PORT" \
        --username="$DB_USERNAME" \
        --dbname="$DB_DATABASE" \
        --format=custom \
        --no-owner \
        --no-privileges \
        --compress=9 \
        --file="${BACKUP_DIR}/${BACKUP_NAME}.dump"
}

compress_and_encrypt() {
    log "Compressing and encrypting backup"
    gzip -c "${BACKUP_DIR}/${BACKUP_NAME}.dump" > "${BACKUP_DIR}/${BACKUP_NAME}.dump.gz"
    openssl enc -aes-256-cbc -pbkdf2 \
        -salt \
        -pass "env:BACKUP_ENCRYPTION_PASSWORD" \
        -in "${BACKUP_DIR}/${BACKUP_NAME}.dump.gz" \
        -out "${BACKUP_FILE}"
    rm -f "${BACKUP_DIR}/${BACKUP_NAME}.dump" "${BACKUP_DIR}/${BACKUP_NAME}.dump.gz"
}

upload_to_s3() {
    local s3_path="s3://${AWS_BUCKET}/backups/$(date +%Y/%m)/${BACKUP_NAME}.dump.gz.enc"
    log "Uploading backup to ${s3_path}"
    aws s3 cp "$BACKUP_FILE" "$s3_path" \
        --region "$AWS_DEFAULT_REGION" \
        --no-progress
    rm -f "$BACKUP_FILE"
}

apply_retention() {
    log "Applying retention policy"

    log "Pruning daily backups (keep ${RETENTION_DAILY})"
    aws s3 ls "s3://${AWS_BUCKET}/backups/" --recursive --region "$AWS_DEFAULT_REGION" \
        | grep -E '\.enc$' \
        | sort -r \
        | awk -v keep="$RETENTION_DAILY" 'NR>keep {print $4}' \
        | while read -r key; do
            aws s3 rm "s3://${AWS_BUCKET}/${key}" --region "$AWS_DEFAULT_REGION" || true
        done

    log "Pruning weekly backups (keep ${RETENTION_WEEKLY})"
    local week_count=0
    local last_week=""
    aws s3 ls "s3://${AWS_BUCKET}/backups/" --recursive --region "$AWS_DEFAULT_REGION" \
        | grep -E '\.enc$' \
        | sort -r \
        | while read -r line; do
            local key=$(echo "$line" | awk '{print $4}')
            local week=$(echo "$key" | grep -oE '[0-9]{8}' | cut -c1-6)
            if [ "$week" != "$last_week" ]; then
                week_count=$((week_count+1))
                last_week="$week"
            fi
            if [ "$week_count" -gt "$RETENTION_WEEKLY" ]; then
                aws s3 rm "s3://${AWS_BUCKET}/${key}" --region "$AWS_DEFAULT_REGION" || true
            fi
        done

    log "Pruning monthly backups (keep ${RETENTION_MONTHLY})"
    local month_count=0
    local last_month=""
    aws s3 ls "s3://${AWS_BUCKET}/backups/" --recursive --region "$AWS_DEFAULT_REGION" \
        | grep -E '\.enc$' \
        | sort -r \
        | while read -r line; do
            local key=$(echo "$line" | awk '{print $4}')
            local month=$(echo "$key" | grep -oE '[0-9]{8}' | cut -c1-6)
            if [ "$month" != "$last_month" ]; then
                month_count=$((month_count+1))
                last_month="$month"
            fi
            if [ "$month_count" -gt "$RETENTION_MONTHLY" ]; then
                aws s3 rm "s3://${AWS_BUCKET}/${key}" --region "$AWS_DEFAULT_REGION" || true
            fi
        done
}

main() {
    log "=== Starting backup ==="
    if ! check_env; then
        log "Environment validation failed"
        exit 1
    fi

    dump_database
    compress_and_encrypt
    upload_to_s3
    apply_retention

    log "=== Backup completed successfully: ${BACKUP_NAME} ==="
    exit 0
}

main "$@"